Guild icon
swift-developers-japan
開発環境, ライブラリ / rx
Rx, RAC
Avatar
I was looking at RxJava Single, and there is two operators that I need and I would like to add on RxSwift. flatMapMaybe - Same as flatMap but returns a Maybe; toMaybe - Convert Single to Maybe. D...
3:24 AM
多分次のバージョンで追加されるんじゃないかな~
Avatar
3:25 AM
rxチャンネルあったのか
Avatar
omochimetaru 3/7/2018 3:27 AM
今回RxSwift全面投入してるけど型推論のヒントどこで与えるがまだなれない
Avatar
flatMap scan reduce
3:27 AM
ここ
3:27 AM
こいつらの返り値にぶち込めばええよ
Avatar
それはコンパイル時間のための話?
Avatar
omochimetaru 3/7/2018 3:27 AM
do(onSuccess)で printしてたら Void に推論されてひっくり返った
3:27 AM
いや、うまくいかないときとかに
3:27 AM
備えて、仕込みたいけど、仕込み場所が悩む
3:28 AM
返り値ね
Avatar
do(onSuccess)で printしてたら Void に推論されてひっくり返った
これどういうことだろう。
3:28 AM
Single<Void>になっちゃった?
Avatar
omochimetaru 3/7/2018 3:28 AM
そそ
Avatar
flatMapとかガチャガチャ繋いで適当なところにdo仕込むと崩壊する
Avatar
omochimetaru 3/7/2018 3:28 AM
doの方が勝っちゃった
Avatar
あんまりそういうのくらったことないなあ
Avatar
omochimetaru 3/7/2018 3:28 AM
俺的にはdoでこけてほしかった
Avatar
ちなみに単に流れてる値をprintしたいだけならdebugオペレータが楽だよ
Avatar
omochimetaru 3/7/2018 3:29 AM
あ〜それもあるか
Avatar
てかSwiftのprint関数は
3:29 AM
引数が可変長Anyだからclosureにそのまま渡すのはいやの感じ (edited)
Avatar
omochimetaru 3/7/2018 3:30 AM
たしかに。単文で入れるといろいろ起きるのか。
Avatar
型推論ぶっ壊れるべ
Avatar
引数にprint関数のリファレンスを渡すという話?
3:30 AM
do(onSuccess: print)
Avatar
do(onSuccess: Swift.print) こういうことでしょ
Avatar
おー
3:30 AM
そんなんやったことないや
Avatar
omochimetaru 3/7/2018 3:31 AM
do(onSuccess: { print("success") } ) いやまあ今回書いてたのはコレだけどね
3:31 AM
do(onSuccess: { _ in print("success") } ) // ←こうしたらうまくいった。
Avatar
クロージャの代わりにメソッドのリファレンス渡すやつ、selfのインスタンスメソッド渡してうっかりretain count + 1になるのが怖くて積極的に避けてる
Avatar
高階関数で設計すると事故らなくていいよ
3:33 AM
↑昨日これが何話してるか深く理解できた気がする
3:34 AM
let task: Driver<Void> = Observable.just(()) .asDriver { err in print(err) } // drv1 .map { ... } // drv2 .flatMapLatest { ... } //drv3 .map { ... } //drv4 (edited)
3:34 AM
↑こういうときにさ、露出してるのはtask == drv4 のオブジェクトで
3:35 AM
shareReplayLatestWhileConnectedの share的働きって
3:35 AM
Drv4に対するobserverの数に対しては機能してるけど
3:35 AM
drv1, drv2, drv3 についてはメソッドチェーンされてるだけだから、実質絶対にobserverは最大1だよね?
3:36 AM
だからreplay用に保存してるけど、replayが仮に無かったとしても、同じふるまいになるよね。
Avatar
/* 宣言時 */ func 某Handler(キャプチャリスト相当の引数) -> (Observableから流れてくる型) -> Result { return { (Observableから流れてくる型) in メインの処理をここに書く。Selfはキャプチャされるのがわかりやすい。 } } /* 利用時 */ 川 .flatMap(某Handler(アレ, コレ)) ... @hiragram
Avatar
その某handlerってどこに属する関数?
Avatar
クラスに書く
Avatar
selfのインスタンスメソッドか
Avatar
3:37 AM
@omochimetaru retain count数えて~~みたいなことすればいけるのかもしれないけど、現状そんなに効率よくないのは確か
Avatar
omochimetaru 3/7/2018 3:38 AM
んーとだから、メモリのことさえ気にしなければ
3:38 AM
メソッドチェーンの途中でobserverが最大1になるObservableっていうのは
3:38 AM
shareがついてようがreplayがついてようが、ついてなかったばあいと、振る舞いは一緒だよね。
3:39 AM
asDriverしてDriverの川をつなげてるときって、ほとんどの箇所はその「振る舞いは一緒」だから、気にせずチェーンして設計することになる
Avatar
Observable型としてインスタンスを確保したときの振る舞いが
Avatar
omochimetaru 3/7/2018 3:39 AM
最初、「ここはshare replayはいらないはずだからDriverにすべきではない?」って考えから入っちゃってめちゃくちゃ困った
3:40 AM
正しい考えは「Driverで組みたいが余計に生じるshareReplay作用は気にしなくても大丈夫」(露出する最後のオブジェクトだけその特性を気にすれば良い)
3:40 AM
だったのだなあと。
3:40 AM
で、いなみさんはその精神性を批判して↑の記事にしてると理解した
Avatar
shareの属性として
3:41 AM
whileconnectedとforeverだったかな、というのもあって
3:41 AM
この辺がまた関係してくる、driverはwhileconnectedだったから
3:41 AM
概ね問題が出ることはない
Avatar
omochimetaru 3/7/2018 3:41 AM
うん
3:42 AM
shareにおいてはconnectedってのはobserver > 0 の意味で
3:42 AM
whileConnected なら、observer == 0 でunsubscribe, 次1になったらsubscribeってことよね
3:43 AM
foreverだと最初につなげた内部の購読がずっと生きるから永続的なcold to hot変換として機能するはず
Avatar
そうそう
Avatar
omochimetaru 3/7/2018 3:43 AM
1. Driver は、必ずしもHotではない
って記事にもあるのは、 0 になると解除、1で再購読だから
3:43 AM
再購読の部分がcold的振る舞いってことよな。
Avatar
そう
Avatar
omochimetaru 3/7/2018 3:44 AM
ありがとう、理解できてそう
Avatar
ちょっとうろ覚えな部分もあるけどだいたいこんな感じだったと思う🔻 observers.isEmpty? - y -> is first time subscribing? - y -> no reply └ n -> reply latest value <- n ┘
Avatar
ちゃうかったわ
4:04 AM
あったあった
4:06 AM
https://github.com/ReactiveX/RxSwift/blob/12cccb171ad9038251af6883807f0290c1d75a5b/RxSwift/Observables/ShareReplayScope.swift#L222 observers.isEmptyになると、この関数が呼ばれてnillingが走って、その結果としてreplayも無くなるやね (edited)
RxSwift - Reactive Programming in Swift
4:07 AM
なんでシンプルにこう observers.isEmpty? - y -> no reply └ n -> reply latest value
Avatar
omochimetaru 3/7/2018 4:08 AM
RxSwift/RxSwift/Observables/ShareReplayScope.swift
4:08 AM
Scopeってなんだ。
Avatar
norio_nomura 3/7/2018 6:53 AM
do(onSuccess)で printしてたら Void に推論されてひっくり返った
そこでdump() https://developer.apple.com/documentation/swift/1539127-dump
Avatar
omochimetaru 3/7/2018 6:53 AM
↑のケースはコンパイルエラーでした
Avatar
norio_nomura 3/7/2018 6:58 AM
なるほど
Avatar
omochimetaru 3/9/2018 3:59 AM
Single<XXX> をコード補完で出そうとした時に PrimitiveSequence<SingleTrait, XXX> が出てきちゃうね。
3:59 AM
protocol未実装の時の自動生成。
Avatar
あー
4:05 AM
それはtypealiasやからね
4:06 AM
Driver Signalも同じ問題がある
Avatar
omochimetaru 3/9/2018 4:06 AM
typealiasって型システム上でどういう扱いなんだろなあ、さっさと置換されちゃってるのかな?
4:07 AM
この関数の返り値の型はPrimitveSequence<A, B>だけど、定義時点ではalias左辺のSingle<B>で定義されていたよ っていう情報が引っ張り回せれば
4:07 AM
protocolのコード補完のときにはalias左辺側で出せそうよね。
Avatar
ですね、基本CanTypeにするときに全部解決されてたはずです > 置換されちゃってるのかな (edited)
Avatar
typealiasじゃなくて型作っちゃえば問題は起きないし
4:11 AM
いいと思うけどどうなんだろ
Avatar
omochimetaru 3/9/2018 4:12 AM
基本CanTypeにするときに全部解決されてた
なるほど
4:17 AM
@tarunon 直感的には、書いてあるものが、そのまま出てきて欲しいと思うよ (edited)
4:18 AM
あと型体系としても、alias型の左辺側が自然に取り回せないと
Avatar
それはそう
Avatar
omochimetaru 3/9/2018 4:18 AM
いなみさんの言ってる要らない型パラはNoErrorで埋めれば良いとかが (edited)
4:18 AM
いつも展開されちゃってしんどい
Avatar
型パラないtypealiasだと展開されないので、バグ扱いで良いと思います。
Avatar
omochimetaru 3/9/2018 4:24 AM
えっ、マジか
Avatar
public class Gen<T, U> {} public typealias IntGen<U> = Gen<Int, U> public typealias IntIntGen = Gen<Int, Int> public protocol Foo { func foo<U>() -> IntGen<U> func bar() -> IntIntGen } class C : Foo { }
Avatar
omochimetaru 3/9/2018 4:31 AM
実験コード作って戻ってきたらもう投下されてた
Avatar
ストリームが切れた時に発火するオペレータって無いですか? doonErroronCompletedに共通の処理を書きたくない。。。
Avatar
omochimetaru 3/12/2018 9:15 AM
onDisposed は?
Avatar
do(onDisposed)←ココ
Avatar
omochimetaru 3/12/2018 9:15 AM
あってそう
👮 1
9:16 AM
警察絵文字やめいw
9:16 AM
悪いことしてない
Avatar
シーケンスの各種イベントをシーケンスで取り出す、みたいなのは無いですね
9:16 AM
どうしても必要ならProposal上げてみるといいかもしんない
9:17 AM
ただあんまりちょっとおすすめできないかな
Avatar
flatMapの中でdo(onDispose)してたらcomplete/errorとdisposeのタイミングが遠くて期待通りにうごかないというのを踏んだ。
Avatar
あーーー
Avatar
ので安易にonDisposeは使わないほうがよさそうというアレになった。
Avatar
それはそうね
9:17 AM
てかそういうアクロバティックな制御はやらないほうが良いぞ 🚔 (edited)
Avatar
そのバグを埋めたのは私ですごめんなさい
Avatar
omochimetaru 3/12/2018 9:17 AM
手動で変換するなら Observable.create の中で do(onDisposed) に observer ひっかける?
Avatar
↑flatMapの中でやってると結局おなじでない?
9:18 AM
「error/completeのどっちかによってストリームは動作を完了した」というのをフックしたいことがある
9:18 AM
でそれは「破棄された」とは必ずしも一致しない
Avatar
えっとね
Avatar
omochimetaru 3/12/2018 9:19 AM
flatMapの中でさらにObservable.createしないとうまくできない気がするけど
Avatar
一つの川のなかであれもこれもやろうとすると事故るので
9:19 AM
まずやりたいことを分離するところからはじめよう
Avatar
それはそう
9:19 AM
それはそうなのじゃ…
Avatar
omochimetaru 3/12/2018 9:19 AM
ひらりが書いたやつがどういうのだったのか気になる
Avatar
単純に catch したら complete するんじゃあ
Avatar
どうしてもそういう邪道なことがしたい君に~~~
9:20 AM
じゃじゃーんmaterializeとdematerialize
9:21 AM
これはObservable<E>をObservable<Event<E>>と相互変換するオペレーターだぞ
9:21 AM
こいつを駆使すればEvent<E>を一箇所で取り出せるからやりたいことは上手いこと表現できるはずだ
Avatar
@omochimetaru ObservableのonSubscribeでなんかフラグを書き換えて、完了したら戻す、の戻すの部分をonDisposeに書いてあった結果、flatMapの中で使われてるそいつのonDisposeは先送りにされフラグがいつまでも戻らないというのがあったのじゃ
9:21 AM
あー。
Avatar
そんなところでフラグを書き換えるなよw
Avatar
あーー。
Avatar
なんてことをするんだ
Avatar
omochimetaru 3/12/2018 9:21 AM
なるほど 、flatMapの中で使ったから先送り、理解
Avatar
謝罪した
Avatar
@tarunon materialze()を乱用するデメリットありますか?
Avatar
一般に考えられるのはプログラムが難読化してメンテナンスコストが増えることですね
Avatar
やっぱそうだよね
Avatar
仕様を成る可く単純化して簡易なプログラミングでメンテナンスフルにするのが我々の仕事ですよ
👏🏻 3
9:24 AM
しっちゃかめっちゃかなプログラムで良ければそのうちMLで解決できるようになっちゃうかもね
Avatar
樹海のような仕様を無理やりリファクタしてRxに載せようとする過程でonError/onCompleteを共通して扱えるやんけonDisposeと勘違いして使ってしまったワイが悪い
9:25 AM
すまねえ
Avatar
>仕様を成る可く単純化して簡易なプログラミングでメンテナンスフルにするのが我々の仕事ですよ 心に刻んだ
Avatar
なお
Avatar
omochimetaru 3/12/2018 9:29 AM
@tarunon 手元にも今↓あるんだけど・・・ requestStream .do(onSubscribe: { loading = true }, onDispose: { loading = false }) (edited)
Avatar
危険川遊びだ
Avatar
omochimetaru 3/12/2018 9:30 AM
ひらりのやつが遅延したのはなんでなん
Avatar
激流下りは禁止されています 🚓
Avatar
omochimetaru 3/12/2018 9:30 AM
completedしたらdisposedされる気がするんだけど
Avatar
9:30 AM
いやflatMapはちがうやん
Avatar
flatMapの中にぶち込んだからと思われる
Avatar
omochimetaru 3/12/2018 9:31 AM
flatMapの中というのがよくわからんぞ・・・
9:31 AM
buttonClickEvent.flatMapLatest { _ in requestStream .do(onSubscribe: { loading = true }, onDispose: { loading = false }) }.disposed(by: bag)
9:31 AM
これで振る舞いが変わる?
Avatar
それはbuttonClickEventがcompleteしないとonDispose呼ばれないと思うお
9:32 AM
@tarunon あってる?
Avatar
omochimetaru 3/12/2018 9:32 AM
flatMapの中の川がcompletedしたらflatMapした結果もcompleteするんじゃないのか
9:32 AM
あ、それはないか
9:32 AM
えーっと・・・、ひらりがいってるのは
9:33 AM
buttonClickEvent.flatMapLatest { _ in requestStream .do(onSubscribe: { loading = true }, onDispose: { loading = false }) }.do(onDispose: { /* ★1 */ }) .disposed(by: bag) (edited)
Avatar
いや
Avatar
omochimetaru 3/12/2018 9:33 AM
★1の話じゃないん?
Avatar
loading = false
9:33 AM
requestStreamはcompleteはするがdisposeされるのはflatMap自体がcompleteしたときじゃない?
Avatar
まってやで
Avatar
omochimetaru 3/12/2018 9:34 AM
disposedがしなかったから壊れたんじゃなくてさ
9:34 AM
disposeよりも次のonSubscribeが早かったから
9:34 AM
フラグ更新の対応が壊れたとかじゃないんか
9:34 AM
まあでも主張はわかった、検証してみる。
Avatar
onDisposeが(狙ったタイミングで)呼ばれなかったから
Avatar
殊ネットワーキング一般に関して言えば
9:35 AM
状態として表現するべきイベントが結構実は多くて
9:35 AM
APIのResponse/Errorだけでは不十分なので
9:36 AM
きっちりやりたいならステート分けて全部流して、各種分類して使う、みたいなのが正しい
9:36 AM
難しければActionなり特化した構造が提唱されているのでそれに乗る
Avatar
きっちりやりたいならステート分けて全部流して、各種分類して使う、みたいなのが正しい
ぴんとこず
Avatar
とりあえず今の要求だと
9:38 AM
少なくとも読み込み中が取りたいわけだから
Avatar
うん
Avatar
enum Network<Response> { case loading case loaded(Response) } API一般はこの型が正しい
9:39 AM
isLoadingはここから.map { $0 == loading }だし (edited)
9:40 AM
responseはここから.flatMap { .from(as? Response) }で取り出す(enum switch 省略)
Avatar
omochimetaru 3/12/2018 9:40 AM
はは〜ん
Avatar
もし読み込み中のProgressingが取り出したいなら
9:40 AM
enum Network<Response> { case loading(Float) case loaded(Response) } にすれば、進捗も取れるよね (edited)
9:40 AM
そういう、データ構造を作るところからきれいな川創りのデザインはある
Avatar
エラーが起きたらエラー用の画面に切り替えたいとか複雑になっていくな
Avatar
omochimetaru 3/12/2018 9:41 AM
あ〜まあそうなのか
9:41 AM
Stream自体は副作用が無い状態になるわけね。
Avatar
そうしないといけない、そうあるべき
Avatar
@tarunon それ1個のenumでやっちゃうと例えば取得済データ0のときの読み込み中とすでにデータあるときの読み込み中と区別したいみたいなとき困らん?
Avatar
それがやりたいならそういうデータ構造を作る
Avatar
case loadingに今VMが持ってるデータを乗せる?
Avatar
それはつまり、Paginationの話だね
9:43 AM
Paginationは読み込み済みのデータ列というものが常に存在していて、そこにNetworkが相乗りしている形になる
Avatar
omochimetaru 3/12/2018 9:43 AM
それは使う側でcombineLatestとかしたらよくない?
Avatar
その筋で整理するとだな
Avatar
ページネーションは置いといても、起動して最初に1ページ目を読み込むのか、引っ張って更新で読み込むのか、で違うじゃない
Avatar
キャッシュも込みか
9:44 AM
別に上のモデルに限定するわけじゃなくってさ
9:44 AM
やりたいことに合わせて適切に川に流す構造をデザインすればいいだけなので
9:44 AM
キャッシュ込み込みあとから読み込みデータ構造みたいなのを
9:44 AM
ちゃんと考えて作ればいいんすよ
Avatar
キャッシュ?
9:46 AM
キャッシュの話どっからきた
Avatar
起動して最初に1ページ目を読み込むのか、引っ張って更新で読み込むのか、で違うじゃない
ここからエスパーした、違ってたらすまん
9:46 AM
9:46 AM
この差
Avatar
それはさ、最初の読み込みはデータが存在してないんだから
9:47 AM
Optionalにするなり完全にプログラミング上に存在しない状態にするなり
Avatar
「取得済の1ページ目」をキャッシュと呼ぶとそうだな
Avatar
選べば良いんじゃない
Avatar
Optionalにするのはどこ?
Avatar
俺はその手合は完全にプログラム上で存在しないようにするのが好きだけど
Avatar
プログラム上で存在しない ってどういうことだ
Avatar
川が流れ始めるのは最初のAPIRequestを叩いてから
9:48 AM
最初のAPIRequestを叩いてない状態は存在しない
Avatar
subscribeしてから川が流れ始めるまでは1枚目みたいなぐるぐる出しておく ってことかな
Avatar
それでいいんじゃねーかな
9:49 AM
キャッシュ込み込みならまたそれに適切なモデルがある
Avatar
イニシャルフェッチ前にしかそのぐるぐる出さないなら良いんだけどエラー画面からリトライボタン押したらもっかいぐるぐる出して通信を試みたいみたいな感じになると状態に載せたほうがよさそうだけど
Avatar
「適切なモデルを考えて作ろう」これに尽きる
9:50 AM
やりたいことに応じてモデルは変わるはずなんだ
9:50 AM
それをAPI一般にくるめようとするから事故が起こる
Avatar
omochimetaru 3/12/2018 9:51 AM
class AAAViewController : UIViewController { public let a: PublishRelay<Void> = .init() public let disposeBag = DisposeBag() func viewDidLoad() { a.flatMapLatest { uself.request() } .subscribe() .disposed(by: disposeBag) } func onButtonClick() { a.accept(()) } private func request() -> Observable<Int> { return Observable<Int>.just(3) .delay(2.0, scheduler: MainScheduler.instance) .do(onSubscribe: { print("subscribe") }, onDispose: { print("dispose") }) } }
9:51 AM
@hiragram ちゃんとdisposeでるよ
9:51 AM
↑は手元から切り出したからちょっとコード壊れてるけど
Avatar
latestやめてflatMapの中でtake(1)したらどうなる?
Avatar
omochimetaru 3/12/2018 9:53 AM
a.flatMap { uself.request().take(1) } .subscribe() .disposed(by: disposeBag)
9:53 AM
disposeでた。
Avatar
なんか
9:53 AM
rx.deallocatedつかってflatMapの中で川遊びしてない?
Avatar
それはないはず
Avatar
あれやるとオペレーターによってはメモリリーク発生してだな…
9:54 AM
一個修正したけどいっぱいあるのまだ全然手付かずだわ
Avatar
omochimetaru 3/12/2018 9:55 AM
設計の話は置いといて、このトピック自体の、onDisposeとか、complete + 購読解除の挙動に関しては
9:55 AM
きちんと理解しておきたいから気になる(し、自分の理解の上ではこのケースは動くとかんがえられるし実際動くのだが・・・
Avatar
そこのonDisposeが呼ばれなくて大困りしてたはずなんだけどなんでおもちコードは呼ばれるんだろ
9:56 AM
当方最新版ではないです
Avatar
omochimetaru 3/12/2018 9:56 AM
樹海のような仕様を無理やりリファクタしてRxに載せようとする過程でonError/onCompleteを共通して扱えるやんけonDisposeと勘違いして使ってしまったワイが悪い
Avatar
懺悔が再掲された
Avatar
omochimetaru 3/12/2018 9:56 AM
ErrorかCompleteが来たらそのストリームにぶら下がっている購読が消えるのはRx (Swiftに限らない) 設計仕様だと思っていて (edited)
9:57 AM
逆に、「Error や Complete が来たけど、 Dispose していない状態」が存在するとしたら、理解不足なので、知りたい。
Avatar
Error流れた川の後ろにretry繋いでいて
9:58 AM
そこで何か起きてるやも試練かも
Avatar
omochimetaru 3/12/2018 9:59 AM
retryは新しくsubscribeし直すから、エラーで死んだ古いほうがdisposeするのは同じじゃない?
Avatar
だよなぁ
Avatar
omochimetaru 3/12/2018 9:59 AM
do(onDispose)がretryの前だし。
10:00 AM
@hiragram また発生したら教えて!
Avatar
実は何らかの理由でCompletedしてなかったのが修正する過程で治った説だと思うんだけど
Avatar
うん、俺も何か状況の観察ミスがあったものと予想はしてる
Avatar
flatMapうんぬんでDisposeされないを踏んだ、でrx.deallocatedかな?と直感で思った
Avatar
completeする前にdisposeBagがdeinitされてただけっぽいです
Avatar
ひらりの言ってた現象の事?
Avatar
それです〜
Avatar
懺悔してもしたりない
10:28 AM
お命だけは
Avatar
まってまって、disposeBagがdeinitしたら
10:28 AM
disposeして、うまくいかない?
Avatar
えーっと
Avatar
つまりonDisposeが動くのが早すぎた
Avatar
逆なのか。completeもerrorも起こってないのにdisposeするパターンか。
Avatar
!!
Avatar
外側からDisposeされる
Avatar
doのonCompleteが発火しなかった
Avatar
onDisposeは呼ばれるよね?
Avatar
よばれます
Avatar
逆やん
Avatar
使ってたのはonDisposeじゃなくて onComplete , onError で
10:29 AM
外側からdisposeされたから、CompleteもErrorも空振りに終わったと
Avatar
なるほど〜〜〜w
10:31 AM
ということは・・・ 一番最初の
doのonErrorとonCompletedに共通の処理を書きたくない。。。
に対して、 onDispose と回答するのは微妙に間違いなのか。
10:31 AM
外側からDisposeした場合をフックするかどうかの振る舞いが異なる。
10:32 AM
盲点だった。
Avatar
で、おもちがわざわざ検証してくれたflatMapでdisposeするのはたしかにdisposeしていて俺はなにと勘違いしていたのだろうかって感じ
Avatar
いや一つ新たな理解が生えて俺は良かったw
Avatar
onTerminateみたいなのがあると良い?
Avatar
@O6lvl4 「onComplete か onError」に完全に一致する概念のこと?
Avatar
ですです
Avatar
要るのかね・・・
Avatar
今後ストリームは動きませんというタイミングをフックしたい気持ちはあるけど
Avatar
そもそも do が嫌い
👉 2
Avatar
設計が間違ってるといわれたらぐうのねもでない
10:35 AM
ぐう
Avatar
kawa.catchError { Observable.empty() }.do(onCompleted: { }) (edited)
💡 1
10:38 AM
誰かがsubscribeしないといけないけど
Avatar
ああそっか、 .empty() でリカバーすると良いのか。
Avatar
今後ストリームは動きません
これ要するに欲しいのは純粋なTではなく、T&Completedなので、そういう型作ってやったほうがいいなぁ
Avatar
それこそmaterializeで簡単にEvent<T>のストリームに出来るんでそれ良さそう
Avatar
なるほど、それでnext以外でフィルターすれば良いと http://reactivex.io/documentation/operators/images/materialize.c.png (edited)
Avatar
ちなReactiveSwiftの on オペレーターではterminatedとdisposedは分離されてます https://github.com/ReactiveCocoa/ReactiveSwift/blob/bb2a2d6f422f79ebc86a755642ca9bd106578d12/Sources/Signal.swift#L886-L924 (edited)
ReactiveSwift - Streams of values over time
👀 3
Avatar
@hiragram これは朗報なのですが、ほしがってたものが多分次のバージョンくらいには追加されますよ https://github.com/ReactiveX/RxSwift/issues/1580
I was looking at RxJava Single, and there is two operators that I need and I would like to add on RxSwift. flatMapMaybe - Same as flatMap but returns a Maybe; toMaybe - Convert Single to Maybe. D...
3:28 AM
flatMapのトレイト間のアレ
Avatar
わーい!
Avatar
(欲しかったら自分で議論するんや)
Avatar
正しい
3:33 AM
今のプロジェクトおわったらがんばるね
Avatar
まあとりあえずコレに関しては彼がよしなに追加してくれると思うんで (edited)
3:34 AM
アブナイAPI追加しようとしてたら待って!って言うようにだけはしておく
Avatar
omochimetaru 3/13/2018 5:51 AM
@hiragram 前にヒラリが言ってた邪悪なやつ作ってみた https://gist.github.com/omochi/37a18554f3518a046daefce9ff001123
Avatar
なになに
Avatar
omochimetaru 3/13/2018 5:51 AM
・エラーなし ・終了なし ・即座に値が取れる ・初期値が要らない
Avatar
あー
5:52 AM
LazyVariableみたいなやつか
Avatar
omochimetaru 3/13/2018 5:52 AM
LazyVariable知らなかった
Avatar
誰かが提案したけどVariable消すから待ってやでって言われたやつ
Avatar
omochimetaru 3/13/2018 5:52 AM
じゃあそれだ
Avatar
ワイが提案したんやったっけか
Avatar
ワイがLazyVariableしったのはたるのんから
Avatar
omochimetaru 3/13/2018 5:52 AM
I need ReplaySubject wrapper like Variable. I felt we need this wrapper because Variable is required initial value. Motivation Variable is not good way to avoid set initial value. Variable...
Avatar
ワシだった
Avatar
omochimetaru 3/13/2018 5:53 AM
たるリク出た
Avatar
たるリク
Avatar
Replay1Relayみたいなのがあればそれでええね感
5:53 AM
valueの同期アクセスをどうするかは課題だなー
5:53 AM
個人的にはImplicitlyUnwrappedOptionalで表現するのは
5:54 AM
案外筋が良いと思っている
Avatar
omochimetaru 3/13/2018 5:54 AM
BehaviorSubject<Int!>
5:54 AM
てこと?
Avatar
いや
5:54 AM
ああ、まあそうか
5:54 AM
acceptはT
Avatar
omochimetaru 3/13/2018 5:54 AM
あ、.valueをInt! にするのか。
Avatar
にして、valueはT!にする
Avatar
valueが無かったらクラッシュしますよ〜というのがわかるようにってことか
Avatar
そうそう
Avatar
ただなんかに代入するとOptionalでてきちゃうのがなあ
Avatar
代入?
Avatar
omochimetaru 3/13/2018 5:55 AM
ワイのはread 即 死亡
Avatar
でも実際に欲しいのは
Avatar
omochimetaru 3/13/2018 5:55 AM
let a = xProp.value // 左辺が Int? になる
Avatar
Replay1Relayで、同期アクセスは無くてもオッケーなパターンが多い気がするので
5:55 AM
ははぁ
Avatar
omochimetaru 3/13/2018 5:56 AM
同期アクセスがほしいっていうのが先にある要望じゃない?
Avatar
フーム
Avatar
omochimetaru 3/13/2018 5:56 AM
UIKitのデリゲートとかで現在値を返したいとか。
Avatar
IUOの出番じゃないスかね…
Avatar
@tarunon 代入でOptionalでてくるのこれ let hoge: Int! = 1 // Int! let fuga = hoge // Int?
Avatar
なんかに代入すると…ってのは型がわかっていれば事故らないので
5:57 AM
別にそんなに遭遇しない気はするけど
5:57 AM
あーーーー
5:57 AM
わかった
Avatar
結構ある気がするけどな
Avatar
またひらりが磔刑になるパターンだけど
🎃 1
Avatar
おう
Avatar
それは後で
Avatar
ええよ
Avatar
とりあえず
5:58 AM
エスパーするとだな
5:58 AM
var x = relay.value x.mutate() relay.accept(x) こういうことしてない?
Avatar
ん?
5:59 AM
あいや別に手元に具体的なコードがあるわけでなく
Avatar
まあなんか、極力同期アクセスしなくても良いようにコード書いたほうが良いよって話なので
5:59 AM
そういう話をあとでしよう
7:27 AM
ここのマーブル、ドラッグできたの・・・
7:27 AM
絵じゃなかった・・?
Avatar
それがメイン機能やぞ
Avatar
omochimetaru 3/14/2018 7:27 AM
え、ずっと昔から?
Avatar
少なくとも僕がRxのオベンキョ始めた時はうこがせたよ
Avatar
オペレーターによっては絵のやつもあったかも。
Avatar
爆笑してる
Avatar
omochimetaru 3/14/2018 7:28 AM
・・・・
Avatar
Learn, build, and test Rx functions on Observables
Avatar
インタラクティブダイアグラム
Avatar
omochimetaru 3/14/2018 7:28 AM
そのサイトは知ってたんですよね。
Avatar
RxMarbles すら絵だと思ってた…
😶 1
Avatar
omochimetaru 3/14/2018 7:29 AM
wwwww
😭 1
Avatar
あー、reactivexのドキュメントの方はどうだろ
7:29 AM
rxmarblesと勘違いしてるかも
Avatar
omochimetaru 3/14/2018 7:29 AM
そっちはインタラクティブって上にかいてあるじゃんw
7:29 AM
いやそうそう、ReactiveX公式のやつが動かせるのを今知った (edited)
7:30 AM
これとかは絵
Avatar
omochimetaru 3/14/2018 7:30 AM
あ!ですねですね!
Avatar
「ドキュメント見てもよくわからん、rxmarblesみよ」というのはやったことあるので動かない時代があったのは確かか
Avatar
omochimetaru 3/14/2018 7:30 AM
@hiragram でも実はその時ドラッグできた可能性
Avatar
それはもうバッドUIと思いたい
7:30 AM
動かせる感だしてほしい
Avatar
omochimetaru 3/14/2018 7:31 AM
うん、いますごくそういう気持ちになっている。
7:31 AM
プルプルしててほしい。
Avatar
なんでみんな RxMarbles いいってそんな言ってるんだろうと思ってた(情弱)
Avatar
omochimetaru 3/14/2018 7:31 AM
ビアッコ面白すぎ
😇 1
Avatar
textField.rx.textってtextField.textを書き換えても変わらんのか。
10:58 AM
これなんじゃが
11:00 AM
ViewModel側にtext: BehaviourRelay<String>用意してそっちを書き換える、textField.rx.textはvm.textと双方向バインディングする、が割りとスタンダード感ある
11:01 AM
この辺はCocoaの思想を色濃く受け継いでいて、Cocoaって基本的にプログラムによって発生したイベントの結果はDelegateから出てこないじゃん、あれと同じ動きになってる
Avatar
でもデリゲート起点でまた.textに書き戻すのは変じゃない?
11:02 AM
VM更新でviewも変わってほしいという要求と、 現在の値が取れるストリームが欲しいという
Avatar
textView.rx.textはオートコレクトの変更を受け取る手段が無いので、例外的に入力を直接出力するようになっている。
11:04 AM
うーん、何やりたいかによると思うんだけど、これ俺が毎回言っていることで
Avatar
なんか二つリレーおけばうまくいきそうなんだけどこんがらがってる
Avatar
TextFieldの状態ってStringだけじゃないんだわ、カーソル位置、未変換のレンジ、本当はAttributeもある。
Avatar
うん、だから
Avatar
こいつらを全部ちゃんと取りまとめて扱わないといけないんだけど、UIKitはそれ用意してないんだよね
11:05 AM
なので双方向バインディングは極力やるべきではない。崩壊するから。
Avatar
うむ
11:05 AM
やりたくないので
11:05 AM
やらずになんとかしたい
Avatar
let output = Observable.merge(textField.rx.text, vm.text) input.bind { input in Disposables.create( input.bind(to: textField.rx.text), input.bind(to: vm.text) ) } とりあえずはこれで解決できないかな (edited)
11:07 AM
もうちょっとキレイにするわ
Avatar
あ、そっか
11:07 AM
vmとイベントをコンバインするだけかも
Avatar
ん?コンバインじゃなくてマージでよくね
11:08 AM
修正しといた
Avatar
ああマージだ
11:11 AM
なんかまだコード変では
Avatar
なんか変かしら
Avatar
まずコロンの横に型ないし
Avatar
変だわw
11:12 AM
でもさすがにそれくらいはわかるっしょ~~
11:12 AM
なおした
Avatar
inputは何?
Avatar
ObservableType where E == String
11:13 AM
まあなんでもええねん
Avatar
ああ。アプリ側の計算結果ね。
11:14 AM
俺の感覚とin outが真逆だ。
Avatar
その辺はユースケースで変わるやろ、結局言いたいのはIOを2方向に流して取ればやりたいこと出来るから
11:14 AM
それで頑張れって話なのだ
Avatar
なんかまあできそうだ
11:15 AM
ありがとう
Avatar
そういえばプロパティ直接書き換えるのをやめろwithLatest使え話をまだしてなかった
Avatar
あ、それにはたどり着いた
Avatar
お、じゃあおもめた.bind(to: ひらり)でやってもよさそうやな
Avatar
nあんや
Avatar
川に同期アクセスしたい病を減らす処方箋 (edited)
👍 1
Avatar
このまえはなしたやつか
Avatar
物事の川とbehavRlyをwithで混ぜてbhvRlyに戻す形
Avatar
必要なら全部流せってやつね
Avatar
それだけではないが別のWayも
11:18 AM
コレコレフラグ: BehaviorRelay<Bool> みたいなのがあった時に、ボタンを押したらひっくり返したい
Avatar
ただDriverのwithLatestが引数1このやつしかなくて不便
Avatar
どうする?がクイズね
11:18 AM
プロポーザル出すんや
Avatar
コンパイル遅くなるから渋ってるのかなと思った
11:19 AM
それとも、いろいろ保守的に少しずつ実装してることが多いの?
Avatar
必要なシナリオとコード添えて、それでもないのはコンパイルでambiguousが出るからかな?みたいな感じでPRタテたら
Avatar
選択的にやってるのかたんに今そうなのかの温度感がわからない
Avatar
シュッとマージされると思うよ
11:20 AM
あー温度感は、必要な人間が必要だと思ったら追加する感じだと思う
Avatar
あとは自分の感覚がトンチンカンなのか確信がないのもあるな
11:20 AM
なるほど
Avatar
まあそこはさ、PR立てたら教えてくれるんやから
11:21 AM
やったらええやん
Avatar
案件落ち着いても意見同じだったらやる
👍 1
11:22 AM
いま初動でいろいろ試してるんや
Avatar
ところでさっきの解答なんだけど
11:24 AM
// △ button.rx.tap.bind { フラグ箱.accept(!フラグ箱.value) } // ◎ button.rx.tap .withLatest(from: フラグ箱) .map { !$0 } .bind(to: フラグ箱) って感じです (edited)
Avatar
うむ
Avatar
あーなんかオペレーターがRACと混じってるかも。まあ雰囲気わかるっしょ
Avatar
withLatestだと見るだけだけど、 combineLatestだと水圧もかかるから壊れるやつね
Avatar
そうそう、というか後者だとそもそもフラグ箱が同期アクセス出来る必要もなくなるというメリットがあって
11:25 AM
これが大きい
Avatar
前者ようなの命令型混合でやると
11:26 AM
非同期タスクの中断とかが
Avatar
せやね
Avatar
泥臭くなっていくことがわかってきた
Avatar
omochimetaru 3/28/2018 2:22 AM
ある川AがNext X を発行した時、 別の川Bの最新の値がある値YならばそのNextを通して、 もしそうでないならば、BがYを送り出すまで待って、Yが来たらXを流す っていう制御をしたかったんだけど
2:22 AM
昨日結構悩んだんだけど、 A.flatMap { x in B.filter(isY).take(1).map{ _ in x } } だった。flatMapすごい。 (edited)
Avatar
LatestかFirstにしたほうが良さそう
Avatar
omochimetaru 3/28/2018 2:24 AM
flatMapFirstでもflatMapLatestでもなくて、flatMapの内側のtake(1)というのも 新しかった
Avatar
あーtakeがある
Avatar
omochimetaru 3/28/2018 2:24 AM
それだと、Bの川が流れるたびに出ちゃうんだけど
Avatar
待ってる間に先の川に流れて来たやつをどうしたいかによる
Avatar
omochimetaru 3/28/2018 2:24 AM
あくまでAの川をBの川で整流する感じなんだよね。
2:26 AM
Bの川を待ってる間にAの川に2つ目が来ちゃった場合だよね
Avatar
Avatar
omochimetaru 3/28/2018 2:26 AM
その場合は一緒にBをまって一気に2個出る感じだね まあ、実際のシナリオではそれは起きないんだけど。
Avatar
でも整流って言葉を聞くにfirstもlatestもいらなそうっておもったのでよさそう
2:27 AM
うんうん
Avatar
omochimetaru 3/28/2018 2:27 AM
実シナリオとしては、 ネットワーク通信と、演出のアニメーションが同時に走ってて
2:27 AM
もしネットワーク処理のほうが即座に終わってしまった場合でも演出の終わりを待ちたかった。 (edited)
Avatar
それやとcombineLatestの方が楽そうやけど
2:41 AM
AとBがあって両方揃ったらGoになる
Avatar
omochimetaru 3/28/2018 2:41 AM
1回だけならそれでいいんだけど
2:41 AM
viewDidAppaerから発火していて、また表示された場合も正しく作ろうと思った
2:42 AM
(実際にはまた表示されるシナリオは無いんだけど・・・
Avatar
そしたら回数は1:1?
2:42 AM
その場合はzipやね
Avatar
omochimetaru 3/28/2018 2:42 AM
うん、そこまでは思いついたが、1:1じゃない場合 もろもろのタスクが終わる前に高速に画面がdisappar/appaerした場合などでも
2:42 AM
正しそうな設計を考えた(実際には(ry
Avatar
うーん
Avatar
omochimetaru 3/28/2018 2:43 AM
実際CombineLatestで最初作って、考慮してzipにしようとして
2:43 AM
なんか意味論がおかしいなとおもって。
Avatar
なんかね、CombineLatest使って、制御側の方をタイミングベースじゃなくてBool値にして
Avatar
omochimetaru 3/28/2018 2:44 AM
気持ちとしてはAの川をBのタイミングで時間軸方向に整えたいので。
Avatar
filterした方が色々と楽な気がするよ
Avatar
omochimetaru 3/28/2018 2:44 AM
それだと
2:44 AM
Boolのほうが連続で来るとおかしくなるんよな
2:44 AM
まあ、distinctUntilChangedとかあるけど。
Avatar
viewDidAppear.flatMapLatest { .combineLatest(animation, network) } ↑やとだめな理由は、networkのキャンセルはしたくないとか?
Avatar
omochimetaru 3/28/2018 2:49 AM
あーまあそれでもいいのかな・・・? アニメーション周りの仕様変更に柔軟に対応しやすいように、バラバラに書いてるんだよね
2:50 AM
たとえばviewWillappearでなんか発火するみたいな
2:50 AM
変化があったりするかもしれないし
2:50 AM
直感的にその2つの結合度を下げてる
Avatar
まあ理想的にはnetworkはwillで叩いてanimationはdidで叩くのが賢そうではあるね
Avatar
omochimetaru 3/28/2018 2:54 AM
たしかにw
2:54 AM
0.3秒ぐらい稼げるな。
Avatar
初書き込み失礼します 💦 A.withLatestFrom(B.filter(isY)) { x, _ in x } でどうでしょうか?
Avatar
omochimetaru 3/28/2018 5:17 AM
それだと、1回目のBが残っていて、2回目のAと紐付いてしまうんです
Avatar
あ、なるほど
Avatar
omochimetaru 3/28/2018 5:18 AM
A1, B1, A2, B2 の順番で発生した時、B1とA2がペアになってしまう。
Avatar
それだと元のコードがよさそうですね〜 失礼しました 💦
Avatar
omochimetaru 3/28/2018 5:24 AM
いえいえ 書き込みありがとうございます
Avatar
retryWhenについて質問です 川 .flatMap { i -> Observable<X> in Observable.create { o in do { let x: X = try doSomething() o.onNext(x) } catch let e { o.onError(e) } return Disposables.create() } .retryWhen { (e: Observable<Error>) -> Observable<X> in e.flatMap { if e.condition { return Observable.error(e) } else { return Observable.just(???) // Xを求められるけど何のために? } } } }
5:45 AM
retryされた場合、Observable.createからやりなおしになるので ??? の出る幕はないように感じるのですが、何故これが必要なんでしょうか?
Avatar
retryWhenは任意の型のnextを渡した時にretry、なのでクロージャの返り値はObservabble<X>じゃなくてObservable<Void>で良いです。
5:55 AM
確か
5:55 AM
半年ぐらいRxSwiftやってないからあやふや
Avatar
本当だ。読み違えていました。ありがとうございますー
🙆 1
Avatar
omochimetaru 3/28/2018 6:07 AM
public func retryWhen<TriggerObservable: ObservableType, Error: Swift.Error>(_ notificationHandler: @escaping (Observable<Error>) -> TriggerObservable) -> Observable<E> { return RetryWhenSequence(sources: InfiniteSequence(repeatedValue: self.asObservable()), notificationHandler: notificationHandler) } (edited)
6:09 AM
これタイミングにしか作用しないなら E == Void に制限したほうが
6:09 AM
使う時に混乱が無さそう
6:10 AM
提案Go
Avatar
omochimetaru 3/28/2018 6:11 AM
compactMapは提案したいと思ってる
Avatar
stdlibにはあるからね
Avatar
omochimetaru 3/28/2018 6:11 AM
めちゃくちゃ使う
6:12 AM
Boolの川をtrueのときだけのvoidの川にするとか。
6:12 AM
retryWhenは今思いついただけで試せてないし見落としがあるかも
Avatar
.flatMap { $0 ? .just(()) : .empty() }
Avatar
omochimetaru 3/28/2018 6:12 AM
compactMapは試し中
6:13 AM
型変換もある場合は .flatMap { .from(optional: f($0)) }
6:14 AM
てか、この前もでてきた、enumの
6:14 AM
fetchState.flatMap { .from(optional: $0.success) }
6:14 AM
あるcaseだったらそれがsomeで返るやつの絞込もそれで
6:15 AM
fetchState.compactMap { $0.success } と書けてよろしい。
Avatar
実際には
6:15 AM
関数を外に作っちゃって
6:15 AM
.flatMap(foo)ってやるのがオシャンな気はする
Avatar
omochimetaru 3/28/2018 6:16 AM
flatMapはなんでもできすぎて
6:16 AM
コンテキストが読み取りづらいから
6:16 AM
なるべくflatMapじゃないもので書きたい
6:16 AM
それだとfooを読み解かないと何が起こるかわからないし。
Avatar
読み解かなくてもわかるネーミングにすればいいんじゃないかな
Avatar
omochimetaru 3/28/2018 6:30 AM
enumから個別のケースを取り出すのがOptionalなのはわかるとして、 それを just or empty の Observable で返すのは
6:30 AM
たんにflatMapのシグネチャに適合させるためのアップキャストなので
6:30 AM
名前つけようがなくない?
Avatar
あーまあそうか
Avatar
omochimetaru 3/28/2018 6:31 AM
stdlibのArray(の昔の仕様)だったらそもそもflatMapがArrayじゃなくてOptionalを受け付けられたから通ったようなやつ(サブモナド
6:31 AM
だからそういう意味ではflatMap自体をオーバーパワーに使ってると思うんだよね
6:31 AM
無意味に柔軟性の大きい型(Observable)を経由している (edited)
6:32 AM
.map { f($0) } . filter { $0 != nil } .map { $0! }
Avatar
それはそうだね
Avatar
omochimetaru 3/28/2018 6:32 AM
↑こうも書ける・・・
Avatar
https://github.com/RxSwiftCommunity/RxOptionalfilterNil がありますね
RxOptional - RxSwift extensions for Swift optionals and "Occupiable" types
Avatar
あー・・・
Avatar
--1--2--3--4--5--| こういうストリームを --[1]--[1,2]--[1,2,3]--[1,2,3,4]--[1,2,3,4,5]--| こう変換するのってどうするのがいいんでしょう
3:51 AM
operatorsのドキュメントみたけどそれっぽいのみつけられなかった
Avatar
scan使って頑張る
Avatar
ドヒャー
Avatar
omochimetaru 4/1/2018 3:51 AM
いかにもscanじゃん
Avatar
一撃でできるのがありそうだと思って。
3:52 AM
scan了解
Avatar
それぐらいなら、scan(Int { $0 + [$1] } だと思うけど
Avatar
omochimetaru 4/1/2018 3:52 AM
scan([]){$0+[$1]}
3:52 AM
ほぼ一撃
3:53 AM
かぶった
Avatar
なるほど
3:57 AM
scanあんまりちゃんとつかったことなかったや 確かに
Avatar
omochimetaru 4/1/2018 3:57 AM
scanはarrayのreduceと似てるよ
Avatar
reduceもあるよ
4:03 AM
reduceはsourceのcompが来るまで評価してから最後に1個だけnextを作る
Avatar
なる
4:03 AM
ほしいのはnextのたびにarrayにしてくれるやつなのでscanぽい
Avatar
scanはsourceからnextが来るたびに評価して複数nextを作り、sourceのcompが来たらcompする
Avatar
ありがとう
Avatar
omochimetaru 4/2/2018 4:58 AM
Stateが変わった時にその変更がUI起点ならUIには流さず、 その他の起点ならUIを更新する って思いついて
4:59 AM
Stateがプロパティで今の状態がUIからきてるからどうかをBoolでもったら良いと思ったけど
4:59 AM
Stateを構築するところがcombineLatestだとうまくいかなそうで悩んでる
Avatar
distinctUntilChangedかねぇ
Avatar
omochimetaru 4/2/2018 5:18 AM
どの川の変化だったかを知りつつくっつける方法がわからん
Avatar
omochimetaru 4/2/2018 5:31 AM
パラメータの変更ごとに川を作って State川をwithLatetFromで拾って流し込んでいけばいいだけか。 (edited)
Avatar
combineLatestでまとまってるのがムズいですね。distinctUntilChangedで、uiの値とstateで異なっている場合だけ反映するみたいなのはたまにやりますが。
Avatar
omochimetaru 4/2/2018 6:11 AM
combineLatestでまとめずに、それぞれで A.filter { !$0.fromUI } .withLatestFrom(state) { (a, state) in state.a = a } .drive(state) みたいにやればできるな〜と思いました (edited)
Avatar
.withLatestFrom(state) { (a, state) in state.a = a } なるほど、これなら良さそうですね
Avatar
Xcode9.3 (Swift4.1)+ RxSwiftでコンパイラーの最適化時にクラッシュするみたいです。 リリースする際にはお気をつけて... https://github.com/ReactiveX/RxSwift/issues/1555 https://bugs.swift.org/browse/SR-7064
Short description of the issue: combineLatest/zip operators fail at runtime with latest Xcode 9.3b1 / Swift 4.1 running against iOS 11.3 OR 11.2. Expected outcome: combineLatest/zip operators execu...
👀 3
Avatar
うげー
Avatar
もうswiftのmasterとswift-4.1-branchには修正が入ったので、Swift 4.1.1/Xcode 9.3.1に期待したい……
😇 1
Avatar
ちなみに弊社ではTestFlightにたまたまアップロードしてテストしてたら気づきました > クラッシュ...
Avatar
This PR adds the operator flatMapCompletable on Single, related to what we discussed on #1580
👍 1
🙏 1
Avatar
むっ
7:34 AM
おっ。
Avatar
7:34 AM
求めていたものだ
Avatar
ん? flatapCopletableは必ず { _ in Completable.empty() } を渡してあげなきゃいけない…??
🇲 1
Avatar
フラッタップ 🙃
Avatar
nextの値を良しなに処理してその結果Completeする関数(返り値はCompletableになる)、これを引数に取るのがflatMapCompletableなので、理想のそれが手に入ったと思う (edited)
Avatar
ああそうか、なるほど
Avatar
あと幾つかPrimitiveSequence.flatMapが満たしているべき項目が歯抜けになってるな
10:57 AM
Maybe<T> -> ((T) -> Single<U>) -> Maybe<U>と、Maybe<T> -> ((T) -> Completable) -> Completableが足りない気がする (edited)
Avatar
omochimetaru 4/17/2018 2:49 AM
試しに .do(onDispose: ) でそのDisposeBagのプロパティをnilにしてみたら、 DisposeBag = nil から突入した doOnDisposeの中で 再度 = nil しようとして、LoE踏んでSimultaneous accessでクラッシュした
Avatar
むちゃくちゃしおる
Avatar
omochimetaru 4/17/2018 2:50 AM
Singleのチェーンが稼働中かどうかをDisposeBagがnilかどうかで判定できないかなと思って。
Avatar
LoEって何の略?
Avatar
omochimetaru 4/17/2018 2:51 AM
Law Of Exclusivity
2:51 AM
排他則
Avatar
なる
Avatar
omochimetaru 4/17/2018 2:51 AM
入ってるのは知ってるけどなかなか出会わないからちょっとうれしくなった。
Avatar
そういうのは、Subjectかませて、hasObserverだかなんだか、接続中かどうか見分ける方法が用意されてるからそっち使うのがいい
Avatar
observerの一番observable側にオペレーターつける機能ほしいなって思った
2:00 AM
Observable<Bool> ↓ ... いろいろなこねこね ↓ bindAnyObserver<Bool>
Avatar
mapってあるけど
Avatar
observer側の都合でdistinctUntilChangedであってほしいのでbindとAnyObserverの間にそういうオペレーターを挟めるみたいなAnyObserverの機能みたいなのほしい
2:01 AM
Avatar
mapObserver
2:01 AM
それではない
Avatar
2:01 AM
まって みる
2:02 AM
これは単に値の変換してるだけよね
Avatar
そうやな
2:03 AM
distinctはできない
Avatar
flatMapObserverがあればええんかな?
Avatar
そういう問題でもない気がするが
2:03 AM
えっとね
2:03 AM
そういう場合は受け取り側をObserverではなく
2:03 AM
(Observable)->Disposableにしてあげると
2:04 AM
いいと思うよ
Avatar
2:04 AM
ああ
2:04 AM
なるほど。
2:04 AM
それが一番シンプルか。
2:04 AM
たしかにな
Avatar
bindで渡せるでしょ
Avatar
うんうん
Avatar
そういう場合は受け取り側をObserverではなく(Observable)->Disposableにしてあげると
これでやりたいこと完全にできた。ありがとう
Avatar
一段落したので Xcode 9.3 にあげる (ために High Sierra にあげる) かーと思ったけど野生の勘で調べたら RxSwift release build で死ぬ問題に気づいたけどここで話されていたのか
3:42 AM
9.3.1 に期待待ちってステータスなんすね
Avatar
一応無理やり最適化をOffにすれば起きないバグではあるので
4:12 AM
最適化無理やりoffにするからAppleは早く仕事しろという流れになってる
Avatar
なるなる
Avatar
omochimetaru 8/29/2018 4:55 AM
subscribeOn(MainScheduler.instance) が、たとえ現在MainQueueであっても、 (edited)
4:55 AM
MainQueueにasync投入されてしまうんですが
4:56 AM
違うキューだったときだけMainQueueに投入するsubscribeOnってありますか
Avatar
きびしそう
Avatar
omochimetaru 8/29/2018 4:56 AM
む〜
Avatar
どっちかというとSchedulerの責務なので、そういうSchedulerを定義すればワンチャンある
Avatar
omochimetaru 8/29/2018 4:57 AM
とりあえず今の所いずれにせよメインスレからになるから
4:57 AM
subscribeOnを取り除きます
Avatar
RASだとUISchedulerがそういう挙動をしますね(QueueScheduler.mainに対して) (edited)
Avatar
omochimetaru 8/29/2018 5:10 AM
RxSwiftも observeOn はそうだった気がするんですけど違うかな・・・
Avatar
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
5:13 AM
/** Abstracts work that needs to be performed on `DispatchQueue.main`. In case `schedule` methods are called from `DispatchQueue.main`, it will perform action immediately without scheduling. This scheduler is usually used to perform UI work. Main scheduler is a specialization of `SerialDispatchQueueScheduler`. This scheduler is optimized for `observeOn` operator. To ensure observable sequence is subscribed on main thread using `subscribeOn` operator please use `ConcurrentMainScheduler` because it is more optimized for that purpose. */
Avatar
omochimetaru 8/29/2018 5:14 AM
Maniから呼ばれてたらすぐってかいてありますね
Avatar
subscribeOnには ConcurrentMainScheduler を使えってことのよう (edited)
Avatar
omochimetaru 8/29/2018 5:15 AM
subscribeOn(MainScheduler.instance) として呼び出してました。
Avatar
https://github.com/ReactiveX/RxSwift/blob/d158e7700655114e990313948d2de561d50e1115/RxSwift/Schedulers/ConcurrentMainScheduler.swift#L13-L19 /** Abstracts work that needs to be performed on `MainThread`. In case `schedule` methods are called from main thread, it will perform action immediately without scheduling. This scheduler is optimized for `subscribeOn` operator. If you want to observe observable sequence elements on main thread using `observeOn` operator, `MainScheduler` is more suitable for that purpose. */
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
Avatar
omochimetaru 8/29/2018 5:16 AM
むむむ 違う理由なのかな
5:18 AM
#59 0x000000018e934758 in UIApplicationMain () #60 0x0000000103001330 in main at xxxxxxxxxx #61 0x00000001843a5fc0 in start () Enqueued from com.apple.main-thread (Thread 1) Queue : com.apple.main-thread (serial) #0 0x0000000105de08f4 in _dispatch_queue_push () #1 0x00000001058f9194 in DispatchQueue.async(group:qos:flags:execute:) ()
5:18 AM
メインスレからメインスレに投入されてしまうのは間違いない
5:19 AM
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
5:19 AM
ここにきた
5:20 AM
if DispatchQueue.isMain && currentNumberEnqueued == 1 {
5:20 AM
これか
Avatar
currentNumberEnqueued == 1 これでしょうね
5:21 AM
Streams of values over time. Contribute to ReactiveCocoa/ReactiveSwift development by creating an account on GitHub.
5:21 AM
他のスレッドからすでにSchedulerにジョブがキューされているとしたら、 (edited)
Avatar
omochimetaru 8/29/2018 5:21 AM
うむむ
Avatar
キューに積まずに即時実行してしまうと順序がおかしくなるので (edited)
Avatar
omochimetaru 8/29/2018 5:22 AM
うーん、投入元は全部メインなはずだから
5:22 AM
== 1 を満たして即消化 を繰り返すと期待しているんだけど
5:22 AM
そうじゃないってことか・・・?
5:23 AM
MainScheduler.instanceは共有されてるから
5:23 AM
他のダウンロード処理とかが別スレから投げ込んでいると
5:23 AM
そうなるってことですかね?
Avatar
ありそう
Avatar
omochimetaru 8/29/2018 5:24 AM
むむむ・・・
5:25 AM
そうか
5:25 AM
スケジューラはだから、ただのスレッド変換器じゃあなくって
5:25 AM
スケジューラオブジェクトに対してシリアライズする役割ももってるのか
Avatar
MainScheduler : SerialDispatchQueueScheduler で後者のdocで It is extremely important that this scheduler is serial, because certain operator perform optimizations that rely on that property. とあって、serialであることが重要なので、すでにキューに積まれているのがある場合はそれを抜かしてメインスレッド上だからといって即時実行することはNG、という感じですかね〜 (edited)
Avatar
omochimetaru 8/29/2018 5:30 AM
.subscribeOn(MainScheduler())
5:30 AM
これでやりたいことができたっぽい・・・?
Avatar
なるほど別インスタンス(ってかinitはpublicなんだ)
5:32 AM
別インスタンス上ではキュー順序の問題にならないということで大丈夫そう (edited)
Avatar
omochimetaru 8/29/2018 5:32 AM
まずいことが起こらないか考えてるけど良さそうな気がする・・・
5:32 AM
ありがとうございます!理解も深まった。
Avatar
ここのチャンネルかどうか怪しいのですが、すっきりしてないことがありまして、OSSや会社のプロジェクトなどで、guard let weakSelf = self else { return } or guard let strongSelf = self else { return }のどちらも見受けられるんですが、strongSelfっておかしくないでしょうか?
2:31 PM
button .rx.tap.asDriver() .drive(onNext: { [weak self] in guard let weakSelf = self else { return } // or guard let strongSelf = self else { return } // ??? }) .disposed(by: disposeBag)
Avatar
Kishikawa Katsumi 9/8/2018 3:19 PM
私は使わないですけど、そのスコープにおいて self を強参照しているという意味で弱参照の self に対して strongSelf と名付けるのは理解できます。
👀 1
Avatar
弱参照のselfの名前を変えただけがweakSelf、そのスコープ内で見る場合は strongSelfという解釈でしょうか。 🤔
Avatar
Kishikawa Katsumi 9/8/2018 5:54 PM
weakSelfはまあweakだったselfって感じですかね。まあ短命のオブジェクトでそんなに厳密さが求められるものではないので、気にしなくていいんじゃないですかね。
Avatar
ずっと、weakSelfを使って来ていたのでもやもやしてました。
そのスコープにおいて self を強参照しているという意味で弱参照の selfに対して strongSelf と名付ける
この解釈でスッキリしましたーありがとうございます 😋
(edited)
Avatar
🍤ACエビフライ🔌 10/3/2018 5:54 AM
遅レスですけどweakSelfが強参照なのは私は気持ちが悪く感じて、私はstrongSelfなどを使っています。
5:55 AM
[weak self] で弱参照でキャプチャして、それを強参照にしてstrongSelfに入れるっていうイメージで脳内で理解しています。
Avatar
omochimetaru 10/3/2018 5:59 AM
weakSelf は 「弱参照型の」という意味で weak var で使ってます。 「もともと弱参照だった」という意味で、強参照型の変数として使うというコードもあるんですね。 (edited)
Avatar
Kishikawa Katsumi 10/3/2018 6:02 AM
私も気になってざっとGitHubを検索したんですけど、(「もともと弱参照だった」という意味かどうかはわからないですが)どっちも同程度にあるようでしたね。
Avatar
omochimetaru 10/3/2018 6:03 AM
なるほど・・・
Avatar
weakからstrongに参照帰る時のコードなんですけど、この間岸川さんから教えてもらった、必要なproperty/methodを全部guardで取ってくるっていうのはかなりシックリ来てて、個人prodはそれに寄せてます
6:05 AM
.. { [weak self] in guard let someProperty = self?.someProperty, let someMethod = self?.someMethod, ... else { ... } こんな感じ
6:05 AM
@Kishikawa Katsumi これしばしば引数にselfを入れたいケースが出てくるんですけど、そう言う時はどうしますか?
Avatar
Kishikawa Katsumi 10/3/2018 6:08 AM
クロージャの前でlet controller = selfとするか、諦めてwself的なものを使うか、引数でOpitonalを許容してメソッドの中で再度guard で早期リターンですかねえ。要するに私としてはこれでバッチリみたいな答えは持ってないです。
Avatar
omochimetaru 10/3/2018 6:09 AM
Xcodeが弱参照のselfと強参照のselfで色分けして欲しいな〜・・・
Avatar
Apple のコードだとどうなってるんでしょう?なんでもいいけど一番公式のオススメの名前がほしい・・・。
Avatar
ちょっと 検索した結果 https://developer.apple.com/documentation/uikit/uicloudsharingcontroller if let `self` = self {}
Avatar
正直これはやるw
Avatar
https://github.com/apple/swift-evolution/blob/master/proposals/0079-upgrade-self-from-weak-to-strong.md これも実装されたことだし、今後は guard let self = self { でいいんじゃないでしょか。
This maintains proposals for changes and user-visible enhancements to the Swift Programming Language. - apple/swift-evolution
❣ 1
Avatar
Kishikawa Katsumi 10/3/2018 6:22 AM
shadowingできるなら積極的にshadowしたいですね。
6:22 AM
^ 異論はあるかもしれない。
Avatar
omochimetaru 10/3/2018 6:24 AM
コードだけ見た時に、 弱参照にするのを忘れてミスってselfを強キャプチャしてるのか、 ちゃんとやってるのか、一目でわからないので、避けています
Avatar
yutailang0119 10/3/2018 6:25 AM
guard let self = self else { return } の肯定派が多いのか知りたい
Avatar
omochimetaru 10/3/2018 6:25 AM
クロージャの中にピンクのselfがあると、やや!サイクルか!?ってビクっとしちゃう
Avatar
メモリリークはテストで検知してるのであんまり目視でカバーしてないなぁ
Avatar
🍤ACエビフライ🔌 10/3/2018 6:28 AM
guard let self = self else にしていきたいんですけど、なんかトラブルがあるとかいう話をきいてまだ避けています. どんなトラブルだったかは忘れた 😓
Avatar
`self` だとlldbから見えなくなる、とかだった気がします (edited)
6:29 AM
(だったっけ、記憶があやふや)
Avatar
@rintaro このまえ DM で話したときに if let self = self はよくなさそうって言ってませんでしたっけ?😅
Avatar
@koher それタイポで、「以前の」 `if let self = self` は明文化されていないので使うべきではないという意味でした。
6:31 AM
Apple の UIKit リファレンスに載っているのは知らなかったけどw
Avatar
あ、そうだったんですね!
Avatar
Kishikawa Katsumi 10/3/2018 6:32 AM
クロージャの中にピンクのselfがある
チームでやる場合は機械的にselfをweakにしてシャドウイングでも良いとは思いますが、 それはあまり使わずに必要なselfの先をguardでUnwrapするとしたら^だいたいの場合でベターなんじゃないかな。
👍 1
Avatar
Swift4.2 以降は if let self = self が SE-0079 によって公式にサポートされているので、使ってはだめな理由はないと思いますよ。ただ、おもちさんの言っていることも理解できます。 (edited)
Avatar
Kishikawa Katsumi 10/3/2018 6:33 AM
要するに私は現状ではweakSelfやstrongSelfにするならlet self = selfにしたら良いと思いますが、そもそもselfを使わなくてもいいんじゃ
Avatar
omochimetaru 10/3/2018 6:34 AM
確かに・・・>selfの先をunwrap
Avatar
selfの先をunwrapはマジで良いです。本当に
6:35 AM
唯一困るのがselfを渡さなきゃいけないケースですが、まあレアなので最後にguard let self = selfでもいいかなと思う
Avatar
self (のプロパティ)をアップデートする場合はどうでしょう? (edited)
Avatar
self?.prop = newPropでダメでしょうか
Avatar
Kishikawa Katsumi 10/3/2018 6:36 AM
self?.foo = ですね。 (edited)
Avatar
うーん、前も話しましたが、僕は ?. が続くより最初に guard で落としておきたい派ですね。
Avatar
Kishikawa Katsumi 10/3/2018 6:38 AM
いっぱいあるなら(いっぱいって言っても3、4個くらいから)メソッドに分けるかも、とかも考えますね。
6:38 AM
プロパティの更新に限らず、Rxのsubscribeとかで4行5行になるなら (edited)
6:39 AM
なので、具体的なコードを貼ってくほうがそろそろ良さそうかなと思います。
Avatar
omochimetaru 10/3/2018 6:39 AM
膨らんできたからメソッドにしてself?.hoge()の一行にしちゃう、は僕も結構あります
Avatar
Rxだと必要ならObserver生やすのが一番良さそう
Avatar
Kishikawa Katsumi 10/3/2018 6:40 AM
confirmaOnSubmitButton.rx.tap .subscribe(onNext: { [weak self] _ in self?.isForceValidation = true self?.requestValidation(parameters: parameters) }) .disposed(by: disposeBag)
Avatar
あーーー
6:40 AM
岸川さんWay、たまに困るのがあったw
Avatar
self が解放されてるときって、クロージャの中を実行しなくていいケースがほとんどだと思うんですが、 ?. で無視されるとは言え処理が走ってると思いもよらないコードが走る場合があっていやな感じがするので、盲目的に guard で脱出させたいです。例外的に、 1 行で済む場合は僕も self?. 使います。
Avatar
Kishikawa Katsumi 10/3/2018 6:40 AM
^ いま開いてたコードだけど、これはまあ標準的だと思うんですよ。
Avatar
... { [weak self] in guard let navigationController = self?.navigationController ... else { .... } これっす
Avatar
Kishikawa Katsumi 10/3/2018 6:41 AM
上のコード(私が貼った方)でguard書くかというと私は不要だと思います。かと言ってguardを書いてメソッドの中を展開するというのもナシかなあ。 (edited)
Avatar
もとからOptionalだと二重Unwrapになっちゃうw
Avatar
うーん、僕は岸川さんのコードなら guard 書きたいですね。
Avatar
Kishikawa Katsumi 10/3/2018 6:42 AM
メソッド名で良いのが出てこない場合は一旦そうすることもある。
6:43 AM
self?.navigationController はオプショナルチェインで(.?.?)書いちゃうかな。
👀 1
Avatar
confirmaOnSubmitButton.rx.tap .subscribe(onNext: { [weak self] _ in guard let self = self else { return } self.isForceValidation = true self.requestValidation(parameters: parameters) }) .disposed(by: disposeBag)
Avatar
Kishikawa Katsumi 10/3/2018 6:43 AM
なるほど。アリですね。
6:44 AM
confirmaOnSubmitButton.rx.tap .subscribe(onNext: { [weak self] _ in guard let weakSelf = self else { return } weakSelf.isForceValidation = true weakSelf.requestValidation(parameters: parameters) }) .disposed(by: disposeBag)
Avatar
いや、この場合の意図としては
Avatar
Kishikawa Katsumi 10/3/2018 6:44 AM
^ じゃあこれはどうです?
Avatar
これだとクロージャ式の 1 行目で、この中身は self が解放されてると実行されないことを明治できると思うんですね。
Avatar
NavigationController? として取り出したいので
Avatar
omochimetaru 10/3/2018 6:44 AM
weakSelf良く見えてきた・・・
Avatar
そこ自体はnilでも構わないけどselfは正しくあって欲しいみたいなワガママケースが希にある
6:44 AM
てか
Avatar
omochimetaru 10/3/2018 6:44 AM
サイクルしてないって気持ちが伝わってくる
Avatar
RxならObserver書きましょうマジで
Avatar
weakSelf は命名の問題とおもちの言ってるシンタックスハイライトの問題とのバランスだと思っていて、本質的には weakSelf でも self でも変わらないと思ってます。
Avatar
Kishikawa Katsumi 10/3/2018 6:45 AM
そうか、selfが無いことと、navConが無いことは別でした。
6:45 AM
本質的には weakSelf でも self でも変わらないと思ってます。
これは同意します。
Avatar
ただ、シンタックスハイライトは言語仕様じゃないので、 let self = self の左の self が黒字になってくれれば別にそれで問題がない気がします。
6:46 AM
weakSelf は長いので僕は zelf 派でしたが、そこは好みの世界になってしまいそう・・・。
Avatar
omochimetaru 10/3/2018 6:46 AM
それは嬉しい>黒字
Avatar
Kishikawa Katsumi 10/3/2018 6:46 AM
zelf, clazz...
Avatar
self/zelf this/that class/clazz
Avatar
Kishikawa Katsumi 10/3/2018 6:46 AM
どんどん脱線していくパターン
Avatar
thisに対してthatはオシャン
Avatar
今の状況だと僕は let self = self を使いそうですね。シンタックスハイライトはエディタがイケてないとして我慢。
Avatar
ところで、Rx において特にボタンのコールバックとかだと [unowned self] でも安全じゃないかと思っているのですが、そうでもないんですか?
Avatar
えーっと
6:48 AM
ScrollViewは危険
Avatar
Kishikawa Katsumi 10/3/2018 6:48 AM
常に安全では無いですね。
Avatar
たまにヤバがいます
Avatar
omochimetaru 10/3/2018 6:48 AM
deinitからコールが繋がってくるケースで壊れるらしいです
Avatar
ScrollViewは、_adjustContentOffsetだったかな、これの挙動が凶悪で
Avatar
Kishikawa Katsumi 10/3/2018 6:49 AM
ユニットテストでたまにそういうのが見つかって結構直しました。
Avatar
VCが消えるタイミングでframeが変更されてOffset変更してDelegateを発火するっていう激ヤバ挙動があるので
6:49 AM
割と死にます
Avatar
omochimetaru 10/3/2018 6:49 AM
僕はunowned使ってます
6:49 AM
タルノンに聞いてscrollviewは警戒してるけど。
Avatar
なるほど、VC消えた後に delegate メソッドが流れてくるっていうのは聞いたことはあります。
Avatar
deinit から発火ヤバ・・・
6:50 AM
それって明示的に deinit 書いて delegatenil にすれば問題回避できますか?
Avatar
はい (edited)
Avatar
Kishikawa Katsumi 10/3/2018 6:51 AM
アプリにおいて、イベントのコールバックでunownedを使うメリットはほぼ無いんじゃないですかね。 開発時に早期発見できるからDebugではありかもしれないけど。
Avatar
omochimetaru 10/3/2018 6:51 AM
なるほど。
Avatar
えーっと
6:51 AM
ScrollViewはもうしばらくずっとやばいんで
6:51 AM
私はdeinitでScrollViewのdelegateとkvoを必ず明示的に切るようにしてます
Avatar
omochimetaru 10/3/2018 6:51 AM
この購読接続はDisposeBagで保護してる って意味を付与するためにunownedを使いたいです
Avatar
deinit で必ず切るなら unownded 良さそうな?
Avatar
omochimetaru 10/3/2018 6:52 AM
unowned起因でクラッシュしたときには、なんかパターンを組み間違えてる事のサインになるので、
6:52 AM
バグが複雑化する前に発見できる。
Avatar
Kishikawa Katsumi 10/3/2018 6:53 AM
weakで単にそれが実行されないことと、unownedでクラッシュすることの釣り合いが取れますかね。 Debugでやるのはアリ。
6:53 AM
UIイベントのコールバックにおいてですよ、念のため。
Avatar
unowned を使うのは ! を使うのとかと同じ話だと思っていて、もし nil で呼ばれることが絶対に起こらないならありだと思います。 (edited)
Avatar
たのむObserverを定義してくれ…!
6:54 AM
もちろんObserverでどうキャプチャするかみたいな話はありますけど
6:54 AM
Binderとかいいんじゃないですかね
6:54 AM
参照周り上手にやってくれたはず
Avatar
Kishikawa Katsumi 10/3/2018 6:55 AM
コードを持ち寄って話したい感じがしてきましたね。
Avatar
nil じゃないな。解放されている状態で呼ばれないことが保証されるなら。
Avatar
omochimetaru 10/3/2018 6:56 AM
実際で言うとそういうので落ちたことがほぼないのでどっちでも同じかもです
Avatar
Kishikawa Katsumi 10/3/2018 6:56 AM
nil じゃないな。解放されている状態で呼ばれないことが保証されるなら。
リポジトリを探したら危険な例が出てくるはず。。。
Avatar
yutailang0119 10/3/2018 6:56 AM
「解放されている状態で呼ばれないこと」を表明するために unowned 使ってます
Avatar
Kishikawa Katsumi 10/3/2018 6:56 AM
「解放されている状態で呼ばれないこと」を表明するために unowned 使ってます
これはそんなに自明では無いと思うんですよね。
Avatar
unowned クラッシュが許容できないのと、 ! でクラッシュが許容できないのは同じ話じゃないですか?
Avatar
Kishikawa Katsumi 10/3/2018 6:57 AM
まあでも自明なケースもあるか。
6:57 AM
! も同じだと思いますよ。
Avatar
問題は、 UIKit の実装で想定外の挙動を示す可能性があって、現実的にやばいケースが比較的多いということで。
Avatar
Kishikawa Katsumi 10/3/2018 6:58 AM
UIイベントのコールバック程度であえてunownedも!も使うメリットはないんじゃないかと。
Avatar
yutailang0119 10/3/2018 6:58 AM
ただ、仕組みとしてそれを管理できていないので、凡ミスでクラッシュになる可能性があって、悩んでる感じもあります
Avatar
omochimetaru 10/3/2018 6:58 AM
(みんなみたいにめちゃくちゃ大規模に納品物が配布される経験があまり無いから単に確率が見えてないかも
Avatar
僕は絶対 nil にならないなら ! は積極的に使う派なので、絶対解放されてる状態で呼ばれないなら unowned は一貫性のある選択になります。
Avatar
Binder便利…便利なんやで…
Avatar
omochimetaru 10/3/2018 7:01 AM
tarunonのObserverのやつはコードが見たい。
Avatar
大規模になるに従って、 !unowned が起こすクラッシュが許容できなくなったら if letweak を優先するのがいいバランスなのかなぁ。
7:03 AM
(もう #rx 関係ないですが)僕が疑問なのは、 array[i]i + j とかも同じ問題を抱えてると思うんですが、これらでクラッシュする確率は相対的に小さいから許容できるということでしょうか?
Avatar
Kishikawa Katsumi 10/3/2018 7:06 AM
確率は相対的に小さいから許容できるということでしょうか?
端的にいうとそうですね。
Avatar
絶対におきなければ !unowned で良い、UIKit を使ってるとそこの保証が難しく現実的に問題になるケースが多いから [weak self] を使う、というのは一貫性のある選択ですね。
7:10 AM
絶対に起こらないことを十分にコントロールできるなら unowned 、そうでないなら weak という結論になりそう(当たり前だけど)。あとは、クラッシュしたときのリスクと天秤にかけて。使い捨てのスクリプトなら問題ないけど、クラッシュするたびに被るようなアプリとかだと weak 側に傾く。
Avatar
Kishikawa Katsumi 10/3/2018 7:17 AM
妥当なまとめですね 😇
Avatar
omochimetaru 10/3/2018 7:17 AM
let self = の問題。 (edited)
7:21 AM
似てるの報告ありますね
Avatar
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
8:15 AM
weakの責任を担ってくれて、第一引数がselfで第二引数がvalueなクロージャに展開してくれる有能くんです。
8:15 AM
これを使って、
8:17 AM
lazy private(set) var someBinder = Binder<SomeResult>(self) { (controller, someResult) in // ここにNextの処理を書く。 } someResultObservable.bind(to: someBinder).disposed(by: disposeBag) こうする (edited)
Avatar
omochimetaru 10/3/2018 8:17 AM
なるほどなるほど
8:18 AM
Binderという名前だけど、主たる仕事は T を weak で持って guard else return をかわりにやってくれることか
8:18 AM
あ、エラーはだめとか
Avatar
Targetをweakで持ってくれる。Valueは流れてくるからだいたいstructやね
Avatar
omochimetaru 10/3/2018 8:19 AM
はいってるな
Avatar
Errorは当然だめです
8:19 AM
bindingError、確かPreconditionFailureだったと思う
8:20 AM
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
8:20 AM
これ
Avatar
omochimetaru 10/3/2018 8:20 AM
1行で書ける? someResultObservable.bind(to: Binder(self) { (self, result) in ... }).disposed(by: disposeBag)
8:20 AM
(型推論が死んだりする? (edited)
Avatar
someResultObservable.bind(to: Binder(self) { $0.foo($1) }).disposed(by: disposeBag)
8:20 AM
これでいけそうなもんやが
Avatar
omochimetaru 10/3/2018 8:20 AM
うん
Avatar
でもそもそもBinder側を外で定義した方が良いので
Avatar
omochimetaru 10/3/2018 8:21 AM
そうすると流れで読みづらくない?
Avatar
ProsConsあると思うなー
Avatar
omochimetaru 10/3/2018 8:21 AM
処理的に後に来るものがコード的に前に出てくるのが嫌い (edited)
Avatar
まあプロコン考えて良しなに選択でいいと思います
8:22 AM
適切にエラーハンドリング済んでるんだったら正直Binder使わない手はない
8:22 AM
めちゃくちゃ便利
Avatar
omochimetaru 10/3/2018 8:23 AM
あーそうか、後ろで subscribe (onError : { } ) だとダメだね。 (edited)
8:23 AM
あ、でもUIBindingのところだから
8:23 AM
流れてこなそう。
Avatar
後ろでError書くのはちょっと色々しんどみがあるので、川壊れてるし。
8:23 AM
壊れないようにちゃんとハンドルした綺麗な川をUIに流しましょう
8:23 AM
汚染水はちゃんと処理すること
Avatar
omochimetaru 10/3/2018 8:23 AM
とりあえずBinderは知らなかったので助かったありがとう
Avatar
🍤ACエビフライ🔌 10/3/2018 9:44 AM
RxSwiftで someObservable.voidify() : Observable<Void> みたいなのを自分で書きたくない&管理したくないので、既存のライブラリにあるものを使いたいのですが、ご存知ないでしょうか?
9:44 AM
RxCommunityあたりに存在しそうなんですが...
9:46 AM
余談ですが、nilを無視する .filterNil() ( Observable<Optional<T>> -> Observable<T> ) みたいなのも探していたのですが、それは RxCommunity のRxOptionalにありました。 😄
Avatar
思考停止.map { _ in }マン
9:47 AM
私は結構nopっていうn引数void returnの関数をutilに生やすんですが
9:48 AM
これ使うと.map(nop)になります
9:48 AM
※あくまで個人productの話
Avatar
↓こういうことですか? func nop<T1>(_: T1) {} func nop<T1, T2>(_: T1, _: T2) {} ...
Avatar
そんな感じです
Avatar
🍤ACエビフライ🔌 10/3/2018 9:54 AM
なるほどです。いずれにせよそういうUtil的なものってあんまりプロダクトそのもののコードと一緒に管理したくないという気持ちがあるんですが、 @tarunon さんはプロダクト内に保持されてますか?
9:55 AM
noopいいですね かっこいい感じもする
Avatar
結構お気に入りのやつがあって
Avatar
nop 便利そうだなぁ。
Avatar
undefined<T>とかlazy<T>とか、或いはconst<T>とか
9:57 AM
こういうのは全体から参照される最上位ライブラリに置いてあります。
9:57 AM
lazyはこの間のiOSDCで議論した後に作りました
Avatar
🍤ACエビフライ🔌 10/3/2018 10:00 AM
なるほどです 複数のプロダクトまたがって使ってらっしゃるってことですよね うちは小さなスタートアップだからプロダクト1つしかないし、どうしたものか...
Avatar
あーーーーー!
10:01 AM
私のコード、個人でもMicroFrameworkです
10:02 AM
予めFrameworkは分けておいて、productが複数に増えたらリポジトリ分けるとかでもいいかも。
10:02 AM
1Framework1xcodeprojにしておくと、切り出しも楽です
Avatar
🍤ACエビフライ🔌 10/3/2018 10:03 AM
なるほど! Micro Frameworkにしていきたい... とりあえずRxCommunityとかにないものは今まで通りプロダクト内で保持して、 時期をみてFramework切り分けをしていきたいと思います
Avatar
Framework がたくさんあると起動が遅い問題って解決されたんですっけ?
Avatar
されてないと思いますよ
10:05 AM
なのでFrameworkのライフサイクルは考えないといけないです
Avatar
Framework にライフサイクルってあるんですっけ?
Avatar
あーー
11:06 AM
Stableになったら解体するとか、StaticLibへの移行とか
11:07 AM
そんな感じのニュアンスです
Avatar
ああ、なるほど、実行時の話じゃなくて開発上のライフサイクルってことですね。
Avatar
ですです
Avatar
RxSwiftに compactMap の概念を入れると便利になると思うんですがどうでしょう stream.flatMap { x -> Observable<Foo> in guard x.isValid else { return .error(SomeError()) } guard x.isOnCertainCondition else { return .empty() } return .just(x.foo()) } optionalStream .flatMap(Observable.from(optional:)) いちいちObservableを通すのはソリューションとしてデカすぎると思うんですよね こんなふうに書きたい stream.compactMap { x -> Foo? in guard x.isValid else { throw SomeError() } guard x.isOnCertainCondition else { return nil } return x.foo() } optionalStream .compactMap { $0 } (edited)
Avatar
RxOptional入れるといいのかな
Avatar
Swiftの言語仕様を考えるとこうするの自然に感じるんですが、 RxCommunityを横断して見ると独特な場合は、やはり拡張側で提案すべき?
Avatar
operatorがRx標準じゃないから入れたくないのかな?とか思ってます。
5:01 AM
温度感はわかんないですね
Avatar
自作して入れてる
Avatar
棄却されてる前例はないし、雑にIssue作って聞くだけ聞いてみようかな
5:08 AM
https://github.com/ReactiveX/RxSwift/issues/1712#issuecomment-410499742
There is no correlation between Swift's compactMap and flatMap situation to what Rx's flatMap aims to solve, since they work on entirely different data types and solve very different things.
🤔
Level of RxSwift knowledge: (this is so we can understand your level of knowledge and formulate the response in an appropriate manner) just starting I have a small code base I have a significant co...
Avatar
We use flatMap to transform and filter events. stream.flatMap { x -> Observable<Foo> in do { try x.validate() guard x.isOnCertainCondition else { return .empty() } return x.fooOrNil().map(...
👏 1
👍 2
Avatar
yutailang0119 10/11/2018 5:44 AM
Yoshitaka SekI
🤔 1
Avatar
takasekだ
😋 1
Avatar
ReactiveSwiftにはfilterMapがあった気がする
Avatar
RxSwiftでshareをよく忘れてしまうのですが、SwiftLintなどで警告を出すことは可能でしょうか?または忘れないようにするやり方、こうやってるよなどなんでもいいので教えていただけたらありがたいです🙇
Avatar
Kishikawa Katsumi 11/15/2018 12:03 PM
そういうルールがあるかどうかは知らないですが(たぶん無い)、自分でルールを追加したらいいですよ。 ASTを使ったほうが確実ですが、簡単でいいなら、正規表現だけでもできます。それなら.swiftlint.ymlだけで追加できるので簡単です。
12:05 PM
must_have_weak_cupture_argument_in_subscribe: name: Must have weak capture argument in Rx#subscribe method match_kinds: - keyword - identifier - typeidentifier - attribute.builtin included: "./(Folio|Redux)/.*\\.swift" regex: rx.tap\s\s*.subscribe\(onNext:\s\{\s(?!\[weak) message: Must have weak capture argument in Rx#subscribe method severity: error ^ これはsubscribeの中はweakキャプチャしなければならない、というルールですが、こんな感じで追加したらいいと思います。
🙏 3
Avatar
アドバイスありがとうございます。 ナルホド、自分でルールを追加してしまえばいいのですね。 やったことなかったので挑戦してみます。 ↑のweakもよくつけ忘れるのでありがたく使わせていただきます!
Avatar
Kishikawa Katsumi 11/15/2018 2:08 PM
正規表現でマッチさせるのは簡単ですけど細かい融通は利かないので、バランスを考えつつ増やしていくと良いと思います。
Avatar
🍤ACエビフライ🔌 12/11/2018 1:56 PM
RxSwiftで /dev/null のような、何を流しても無視するダミーのObserverを書くことがちょいちょいあるんですが、(主にredなテストを書く時にコンパイル通る状態にするのにつかう) AnyObserver(eventHandler: { _ in }) とか AnyObserver(eventHandler: nop) とかいちいち書く以外に何かそれ用のものって用意されていたりしませんでしょうか?
Avatar
omochimetaru 8/21/2019 4:00 AM
RxSwiftで MayBe から Single に変換する簡単な方法ってありますか? MayBeがnext無しでcompleteした時に流す値を指定すれば概念上は変換できると思うんですが。
4:01 AM
現状 maybe.asObservable().concat(.just(defaultValue)).take(1).asSingle() しか思いついてないです。 (edited)
Avatar
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
Avatar
omochimetaru 8/21/2019 5:28 AM
おお!
5:28 AM
ありがとう、そんな名前だったのか
Avatar
omochimetaru 9/26/2019 3:03 AM
@propertyWrapper public struct ObservableProperty<T> { private let relay: BehaviorRelay<T> public var wrappedValue: T { get { return relay.value } set { relay.accept(newValue) } } public var projectedValue: BehaviorRelay<T> { relay } public init(wrappedValue: T) { self.relay = BehaviorRelay(value: wrappedValue) } } public final class ServiceContainer { @ObservableProperty public var style: Style = Style() } func main() { let _ = serviceContainer.$style.subscribe { (style) in apply(style) } }
3:03 AM
こんな感じですかね
Avatar
RxSwiftで、can/should系のdelegateってどうやって実装してるんでしょ?
6:36 AM
e.g. textViewShouldBeginEditing()
6:38 AM
e.g. tableView(shouldHighlightRowAt:)
Avatar
https://github.com/ReactiveX/RxSwift/blob/c6c0c540109678b96639c25e9c0ebe4a6d7a69a9/RxCocoa/iOS/DataSources/RxTableViewReactiveArrayDataSource.swift#L15-L37 こんな感じのベースクラスがあって、これを実装したdelegate/dataSourceの実装クラスを DelegateProxyというものに詰めて https://github.com/ReactiveX/RxSwift/blob/c6c0c540109678b96639c25e9c0ebe4a6d7a69a9/RxCocoa/iOS/UITableView%2BRx.swift#L140-L142 呼び出される仕組みになっています(という解答で良いのかな)
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
8:09 AM
DelegateProxyではcanPerformSelectorがproxy先に実装されていればtrueを返すので、そこからproxy先の実装されたメソッドを呼び出して返す。実装されたメソッドは大体のパターンとしてはRxSwiftのもつinternalなオンメモリのデータを見て(ここはstreamではなくそのキャッシュになってることが多い)返す値を決定しています。
Avatar
can/should 系は戻り値があるんですけど、 (edited)
8:10 AM
その変化のイベントはデータではなくて、コントローラーとかビュー自身のイベントなんですよね (edited)
8:11 AM
そういうの、どうしてるのかなあっていう。
8:12 AM
UITableView の datasource はみたんですけど、変化のイベントの発生源はデータ側なので
8:12 AM
ちょっとちがうかなあって。
8:13 AM
で、よくみたら、can/should系は尽く実装されてなくて
Avatar
view側のイベントをフックしてstreamのキャッシュと付き合わせて返り値を決定、と言うパターンになる気がしていて (edited)
Avatar
どうやって解決してるんだろうって思ったわけです。
Avatar
can/shouldあんまり無いのか。 cellを返すところは実装されてるので、そこが参考になるかも
8:14 AM
numberOfRowとcellはあるので、そこかなぁ
Avatar
cell返す(UITabelViewとかのdatasourceですね)のも、トリガーはデータソースのstreamで、reloadData()を呼んで結果的にストリームのイベントに応答してるみたいになってて (edited)
8:15 AM
うぬぬ、って。
Avatar
たしかに辻褄合うように作られてますね
Avatar
だからアノマリーな should系は実装されてないのは
8:16 AM
なんかパターンが存在してないのでは、とも思ったわけです。
Avatar
うーん基本的には
8:17 AM
普通のtableViewの実装と気を付けることは全く同じで
8:18 AM
should/can hogehogeの時にデータ不整合が起きなければいいはず、というか
8:18 AM
あれ、昔見たコードだとdeleteとかもあった気がするんだが…RxDataSourceの方かな…
8:19 AM
UITableView and UICollectionView Data Sources for RxSwift (sections, animated updates, editing ...) - RxSwiftCommunity/RxDataSources
8:20 AM
この辺、ありそうかな?
Avatar
おー。
8:20 AM
見てなかった。
Avatar
これも同じく、イベントフックからキャッシュと付き合わせて返り値を決める、と言うパターン
Avatar
なるほど、、
8:24 AM
なかなかヘビーな感じに、、
8:26 AM
UITableView and UICollectionView Data Sources for RxSwift (sections, animated updates, editing ...) - RxSwiftCommunity/RxDataSources
8:26 AM
こういう感じのがわりといくつか必要みたな雰囲気なのかな。。
Avatar
多分、これ相当の実装を欲しいUIViewのDelegate/DataSource毎に作ることになるのではないかと〜 (edited)
Avatar
なるほど。。
8:32 AM
もうすこしexploreしてみます、ありがとうございます〜
Avatar
本体側に入ってるDelegateProxyのサブクラスとして、キャッシュを持ったクラスを作れば
8:33 AM
似たようなことが出来ると思います。
8:33 AM
ちょっとDataSourceはtableView/collectionViewのお作法が入っててアレなので、PickerView実装とか参考にするとマシかもしれない
Avatar
お作法w
8:39 AM
Reactive Programming in Swift. Contribute to ReactiveX/RxSwift development by creating an account on GitHub.
8:39 AM
この辺ですね
Avatar
ですです
Avatar
うーん return Observable<[Elements]>.create { observer in let realmElements = realm.objects(Elements.self) observer.onNext(Array(realmElements)) let token = realmElements .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } } return Observable<[Elements]>.create { observer in observer.onNext(Array(realm.objects(Elements.self))) let token = realm.objects(Elements.self) .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } } どちらも onNext はちゃんと流れるけど、上だとnextで流れる内容がバグっていることがある、なんでだ (Rx + Realm のはなし
Avatar
内容がバグっている
どうバグっているんだろう。古い値が流れてくるとか?
Avatar
新しいデータが配列に来たときに、何故かどこかの古いデータと同じ内容として流れる
7:01 AM
たとえば
7:01 AM
別所で新しいデータを入れた時、 [A, B, C] に D がきても (edited)
7:01 AM
ここの next でくるのは [A, B, C, C] みたいになる (edited)
7:02 AM
んで上のコードの update のところに print を入れると何故か発生しない (ちゃんと [A, B, C, D] になる) (edited)
Avatar
omochimetaru 2/2/2021 7:08 AM
print入れると治るならマルチスレッド関係のバグかコンパイラの最適化バグじゃないかな
Avatar
そうなんですよねえ
7:08 AM
こういうバグにぶち当たった時、原因がコンパイラぽかったらどう調べればいいんだろう (edited)
Avatar
omochimetaru 2/2/2021 7:09 AM
デバッグビルドでも壊れるの?
Avatar
でっす
Avatar
じゃあ最適化じゃなさそう
7:09 AM
RxSwift extension for RealmSwift's types. Contribute to RxSwiftCommunity/RxRealm development by creating an account on GitHub.
Avatar
そうなんだよね、synchronousStart が true のときの実装を意識してる
Avatar
気になるのはArrayに変換してるところくらいですかねぇ
Avatar
omochimetaru 2/2/2021 7:10 AM
real.objects の呼び出し回数が違うのも関係あるんかな
Avatar
呼び出し回数かあ、でも print で何故か治るんですよね
Avatar
omochimetaru 2/2/2021 7:13 AM
ABCCになるって判断してる根拠は?
7:13 AM
LLDBで見てるだけだと嘘の値が出る事がよくあるよ
Avatar
UI上でも ABCC の挙動でバグっているのと LLDB 見てもそうだったので
Avatar
omochimetaru 2/2/2021 7:14 AM
UI側のバグって可能性は?tableviewのcellのリサイクルのバグとかで。 (edited)
Avatar
あー、なるほど
7:15 AM
新しい値 が入ってきたら、collectionViewと別のViewでも反映するようにしているので、多分無いかなと思っていたけど (edited)
7:15 AM
もっかいみてみます
Avatar
川から流れてきた値をdebugオペレータで確認すると良さそう
Avatar
omochimetaru 2/2/2021 7:16 AM
自分なら、本当にコンパイラが疑わしくなったら、調査しやすいように最小構成のアプリを組むよ
7:17 AM
でもその前にスレッドバグを疑うな。
Avatar
なるほど
Avatar
omochimetaru 2/2/2021 7:17 AM
特にrealm側のマルチスレッド規約がどうなってるかわかんないし
Avatar
そのへん忘れちゃったな
Avatar
omochimetaru 2/2/2021 7:18 AM
一通りいろんな呼び出しがどういうスレッドで走ってるか確認して、 必要なら observeOnでスレッド切り替え入れて解決ということが多い
7:18 AM
「Dを追加する側」のスレッドも調査対象ね。
Avatar
周辺で observeOn で切り替えたけど改善しなかったので、
7:18 AM
あー
7:18 AM
>「Dを追加する側」のスレッドも調査対象ね。
7:19 AM
これ忘れていた
7:19 AM
たしかに、追加する側もフォーカスしてみます
Avatar
omochimetaru 2/2/2021 7:20 AM
ま〜とりあえず、切り分けるべきなのは、
7:20 AM
realmのobserveの時点で壊れた値が来てるのか
7:20 AM
その先の問題なのかどうかだなあ
7:21 AM
realm側ってわかったら内部にprint文入れたりして更に潜るという感じだな(今オープンソースだったよね
Avatar
OSS ですです
7:21 AM
realmのobserveの時点で壊れた値が来てるのか
この時点でも壊れているっぽいので、その先の問題な気がします(ただしLLDB嘘つくっぽいからわからん
Avatar
omochimetaru 2/2/2021 7:22 AM
オープンソースなら最終的に何が起きてるかわからない事はない
7:23 AM
printじゃなくて関数の呼び出しにして、その関数の中でprintするとか、グローバル変数に溜め込む(DispatchQueue.syncで保護する)とかして
7:23 AM
とりあえず信頼できるデータ観測ができる状態にすることを目指す
👍 1
7:23 AM
(UIだとUIのバグや途中のVMでのデータフローでのバグなどの可能性がどんどん組み合わさってしまう)
7:29 AM
家庭くんのいってる .debug オペレータというのもその手段の一つだね
Avatar
アドバイス通り、「Dを追加する側」のスレッドも変えてみたら上の問題あるコードでもうまくいきましたー
8:05 AM
ありがたい。これスレッドの問題としてすすめるべきかな
Avatar
omochimetaru 2/2/2021 8:07 AM
それでなぜ状況が変わった(うまくいくようになった)のか詳細を調べるのが良いと思うよ (edited)
8:07 AM
もしたまたま関係ない理由で治ってるだけだったら再発してしまうので。
8:07 AM
追加する側のコードがどうなってるかと
8:07 AM
関連するrealmのAPIのスレッドセーフティ仕様がどうなってるかを調べる
Avatar
ですねえ、これ同じようなコードが他にあるので調べないと到底リリースするコードに入れれない・・・
Avatar
気になるのはArrayに変換してるところくらいですかねぇ
かていくんのこれ、気になってたのでArray() するのを消して、Observable の return を <Results> にしたらちゃんと動いた
(edited)
Avatar
Avatar
だから、Results -> Array の変換が早すぎた(?)説もあるけど、スレッド前提でも調べているので頭の隅に置く程度にしている
8:54 AM
調べてみてもobserve時にRealmのスレッドポリシー的にはブロッキングとか必要なさそうだし、これ内部実装見るしか無いのかなー (edited)
8:55 AM
Realm is a mobile database: a replacement for Core Data & SQLite - realm/realm-cocoa
Avatar
僕なら次は再現する小さい要素数のプロジェクトを作って、末尾がC, CになるタイミングのArrayへの変換のところをデバッガで潜っていくと思います
Avatar
おっす!最低限のやつ続けて作ってみます
Avatar
omochimetaru 2/2/2021 8:58 AM
observeじゃなくて
8:58 AM
追加してるコレクションだかDBだかのインターフェースのスレッドポリシーだね
Avatar
ふむふむ
Avatar
omochimetaru 2/2/2021 9:00 AM
まあ確かにobserveの呼び出しと何かが競合する可能性はあるけど
9:01 AM
observeの後でやってくるイベントが壊れてるって話だから、タイミングが違う
9:01 AM
俺はRealm触ったこと無いから、「Dを追加する」っていう部分のコードがどういう感じなのか全くわからないのでよくわからん。
9:03 AM
↑さっき張ったリンクはResultsオブジェクトのコードだからそこには書いてないと思った。
9:04 AM
あとは、Realmとは関係なく自分でArrayを取り扱ってるならそのArrayに対するスレッドアクセス違反かもしれない
Avatar
川に流れてくるArrayは毎回Array(...)で作ってるのでそれは無いんじゃないですかね
Avatar
omochimetaru 2/2/2021 9:06 AM
流れる方じゃなくて「Dを追加する」って言ってる部分が
9:06 AM
どんなコードなのかわからないから怪しんでる
9:06 AM
更新と追加が2系統から生じてその時点でぶっ壊れてRealmに入れる前に壊れてるのかもとか思ってる
Avatar
なるほど。
Avatar
omochimetaru 2/2/2021 9:07 AM
Realm自体に insert みたいなAPIがあって、それを呼んでるだけだけど、それがスレッドセーフじゃないとかの線も疑ってる。
Avatar
追加は、別所でダウンロードしたものとかを try realm.add(D) で追加していますね (edited)
9:14 AM
.subscribe { D in let realm = try Realm() try realm.write { realm.add(D) } }
9:14 AM
みたいなかんじ
Avatar
Avatar
freddi
.subscribe { D in let realm = try Realm() try realm.write { realm.add(D) } }
omochimetaru 2/2/2021 9:15 AM
アドバイス通り、「Dを追加する側」のスレッドも変えてみたら上の問題あるコードでもうまくいきましたー
この話からすると、そのコードのどこかで違反が起きてるのでは
Avatar
ですねー
9:16 AM
ここで observeon でThread変えたらうまく言ってたので
9:16 AM
ここが確かにあやしい
Avatar
omochimetaru 2/2/2021 9:17 AM
writeは1回しかされてないの?
Avatar
ですです
9:20 AM
ありゃ、observeon つけても動かなくなったっぽい。
9:20 AM
さっき試した時 多分 print つけたままやってしまった可能性がある;;;すいません
Avatar
そもそもrealmのマルチスレッドのお作法って、ThreadSafeReference使えとかなってませんでしたっけ?
9:24 AM
if isInWriteTransaction { try commitWrite(withoutNotifying: tokens) }
9:24 AM
Realm is a mobile database: a replacement for Core Data & SQLite - realm/realm-cocoa
9:30 AM
Swift→ObjC→C++って構造になってるっぽい (edited)
9:31 AM
begin_transaction の先頭に verify_thread というメソッドの呼び出しがあるので
9:31 AM
.write でスレッド違反してればここで引っかかりそうだから、.write してるところのスレッドは関係ない気がする
Avatar
そもそもwrite側でスレッド違反してる場合はクラッシュするはず(記憶が正しければ)
9:32 AM
もちろん抜けはあるかもしれなけれど…
Avatar
omochimetaru 2/2/2021 9:32 AM
↑のコードだとその記憶と一致する
Avatar
スレッド違反は、realmオブジェクトが作られたスレッドとrealm.writeの呼び出しが異なると起きる
9:36 AM
writeをしたrealmオブジェクトとreadをしたいrealmオブジェクトが異なるスレッドに存在する場合は、ThreadSafeReferenceを使わないと、そもそも結果は保証されない、だったと思うよ
Avatar
omochimetaru 2/2/2021 9:36 AM
おお
Avatar
流石に5年くらい前の記憶だからあやふやだが
Avatar
omochimetaru 2/2/2021 9:37 AM
void Realm::verify_thread() const { if (m_scheduler && !m_scheduler->is_on_thread()) throw IncorrectThreadException(); }
9:37 AM
このverifyは自身のスレッド所属を確認しているだけなのか。
Avatar
なるほど、write側ではreadが存在するか知らないからverifyできないのか
Avatar
omochimetaru 2/2/2021 9:38 AM
じゃあまだそのあたりのバグの可能性が捨てきれないな
Avatar
printしたら云々は、マルチスレッドになってるんであればどこかのお作法でやらかしてるが9割ぐらいな気はするね
Avatar
omochimetaru 2/2/2021 9:40 AM
printでタイミングずれて助かるやつね
Avatar
printがstdoutに出力するタイミングでスレッドに対して作用とかないんでしたっけ
Avatar
omochimetaru 2/2/2021 9:41 AM
正確にしらんけど、システムコールを呼ぶ事になるから制御がカーネルに移って、
9:42 AM
カーネルのスレッドスケジューラ(CPUに割り当てるスレッドを決めるやつ)がスイッチしたりするという理解
Avatar
そうだよね
Avatar
omochimetaru 2/2/2021 9:42 AM
それか単純にカーネルに移ってる事による時間消費が長い
Avatar
なのでprintの有無は条件がまるで違っていて
Avatar
omochimetaru 2/2/2021 9:42 AM
普段はスレッド切り替えはタイマー割り込みなので
Avatar
これで疑うべきはロックとかトランザクションとかのやらかしって感じになる
Avatar
omochimetaru 2/2/2021 9:43 AM
数行のコードなら途中で止まる確率はめちゃくちゃ低い
9:43 AM
コードの実行のほうがスレッド切り替えまでのタイムスライスよりはるかに早いから。 (edited)
Avatar
最低限のアプリ実装して動かしても再現できなかった。。。。うーん
10:13 AM
ThreadSafeReference
これつかってみますmm
Avatar
Avatar
freddi
うーん return Observable<[Elements]>.create { observer in let realmElements = realm.objects(Elements.self) observer.onNext(Array(realmElements)) let token = realmElements .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } } return Observable<[Elements]>.create { observer in observer.onNext(Array(realm.objects(Elements.self))) let token = realm.objects(Elements.self) .observe { result in switch result { case .update(let data, _, _, _): observer.onNext(Array(data)) case .error(let error): observer.onError(error) default: break } } return Disposables.create { token.invalidate() } } どちらも onNext はちゃんと流れるけど、上だとnextで流れる内容がバグっていることがある、なんでだ (Rx + Realm のはなし
これ、比較的でかいデータを送る && 少々配列が大きくなる とどちらのコードもうまく動かなくなる事がわかりました (edited)
10:57 AM
そしてThreadSafeReference だとなおった・・・
Avatar
ちゃんとお作法は守ろう
Avatar
みなさんありがとうございますmm
10:57 AM
ですねー
10:57 AM
ThreadSafeReference お恥ずかしながら知らなかった
10:58 AM
3年Realm書いてるのに・・・
Avatar
俺の残したコードになかった?なかったならすまん
10:58 AM
全部メインスレッドでやってたかもわからんね
Avatar
これここで言っていいのだろうかw
Avatar
なかったならないで話は終わり
Avatar
ですね
Avatar
omochimetaru 2/2/2021 10:59 AM
ドキュメントはあった?
10:59 AM
ThreadSafeReferenceについての。
Avatar
Realmのオフィシャルの話ならその手のドキュメントは沢山ある
Avatar
omochimetaru 2/2/2021 10:59 AM
なるほど
10:59 AM
それRealm触るなら絶対知ってないといけない知識に見える
11:00 AM
スレッドバグはこのように発生してからだとすごい時間を食うし・・・
Avatar
まあそれはそう、メインスレッド縛りやるならいらんけど
Avatar
そうですね、だた公式のDocが404返すというかんじなので Stack overflow みたり、断片的に残っているやつ見ました
Avatar
omochimetaru 2/2/2021 11:01 AM
あー
11:01 AM
事業が終わっちゃったから、ドキュメントとかは保守がアレなのか
Avatar
omochimetaru 2/2/2021 11:02 AM
なんか
11:02 AM
修正箇所めちゃくちゃたくさんありそうだけど
11:02 AM
がんばれ・・・
Avatar
修正期間大量にあるので、ゆっくりFixしまっす
11:04 AM
ともあれお三方ありがとうございました、、、
Avatar
omochimetaru 2/2/2021 11:05 AM
コンパイラのバグじゃなかったようだな😎
Avatar
はずかし〜〜〜〜
11:05 AM
コンパイラのバグ、見つけたら見つけたで面白かったのにぃ (edited)
Avatar
omochimetaru 2/2/2021 11:06 AM
「コンパイラのバグかもしれない」って考えちゃうと思考停止に繋がりやすいからギリギリまで堪えたほうが良い
👍 1
Avatar
経緯見た瞬間に当てたから、俺の勝ちやな。次回の挑戦をお待ちしております。
Avatar
ケイスケホンダ 許されない
Avatar
流石や、、、
Avatar
ThreadSafeReferenceの実装は、確か書いたことがあると思うんだけど、もしかしたら個人のコードだったかもしれない
11:09 AM
ちょうどTwitterやらマストドンのクライアント書いて遊んでたのがその頃だから、そっちかなぁ
Exported 1,117 message(s)
Timezone: UTC+0